Add initial board, HAL, and executor modules
This commit is contained in:
1 parent
3b9e129c88
commit
0b2eebe76d
82 files changed
+20611
No files matched your search
@@ -0,0 +1,247 @@
|
||||
#include "audio_codec.h"
|
||||
#include "esp_log.h"
|
||||
#include "es7210.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "AudioCodec";
|
||||
|
||||
// 静态成员初始化
|
||||
AudioCodec* AudioCodec::instance_ = nullptr;
|
||||
SemaphoreHandle_t AudioCodec::mutex_ = nullptr;
|
||||
|
||||
AudioCodec::AudioCodec()
|
||||
: board_handle_(nullptr),
|
||||
is_initialized_(false),
|
||||
current_mode_(AUDIO_CODEC_MODE_DECODE),
|
||||
current_volume_(100)
|
||||
{
|
||||
}
|
||||
|
||||
AudioCodec::~AudioCodec() {
|
||||
Deinitialize();
|
||||
}
|
||||
|
||||
AudioCodec* AudioCodec::GetInstance() {
|
||||
// 双重检查锁定模式确保线程安全
|
||||
if (instance_ == nullptr) {
|
||||
if (mutex_ == nullptr) {
|
||||
mutex_ = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(mutex_, portMAX_DELAY) == pdTRUE) {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new AudioCodec();
|
||||
}
|
||||
xSemaphoreGive(mutex_);
|
||||
}
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::Initialize() {
|
||||
if (is_initialized_) {
|
||||
ESP_LOGW(TAG, "AudioCodec already initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Initializing AudioCodec");
|
||||
|
||||
esp_err_t ret = InitializeBoard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio board: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 先设置初始化标志,然后启动编解码器
|
||||
is_initialized_ = true;
|
||||
|
||||
// 默认启用双向模式,同时支持播放和录音
|
||||
ret = StartCodec(AUDIO_CODEC_MODE_BOTH);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start codec in both mode: %s", esp_err_to_name(ret));
|
||||
is_initialized_ = false; // 如果启动失败,重置标志
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "AudioCodec initialized successfully with both encode and decode enabled");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::InitializeBoard() {
|
||||
// 初始化音频板
|
||||
board_handle_ = audio_board_init();
|
||||
if (board_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio board");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Audio board initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::StartCodec(audio_codec_mode_t mode) {
|
||||
// 检查音频板是否已初始化,而不是检查整体初始化状态
|
||||
if (board_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Audio board not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
switch (mode) {
|
||||
case AUDIO_CODEC_MODE_DECODE:
|
||||
ESP_LOGI(TAG, "Starting codec in decode mode");
|
||||
ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START);
|
||||
break;
|
||||
|
||||
case AUDIO_CODEC_MODE_ENCODE:
|
||||
ESP_LOGI(TAG, "Starting codec in encode mode");
|
||||
ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_ENCODE, AUDIO_HAL_CTRL_START);
|
||||
if (ret == ESP_OK) {
|
||||
// 设置ADC音量
|
||||
ret = audio_hal_set_volume(board_handle_->adc_hal, 100);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
// 设置ES7210麦克风增益
|
||||
ret = es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to set ES7210 gain: %s", esp_err_to_name(ret));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ES7210 gain set to 37.5dB");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_CODEC_MODE_BOTH:
|
||||
ESP_LOGI(TAG, "Starting codec in both modes");
|
||||
ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
|
||||
if (ret == ESP_OK) {
|
||||
// 同时设置播放和录音参数
|
||||
audio_hal_set_volume(board_handle_->adc_hal, 100);
|
||||
es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid codec mode: %d", mode);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start codec: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
current_mode_ = mode;
|
||||
|
||||
// 设置初始音量(仅在播放模式下)
|
||||
if (mode == AUDIO_CODEC_MODE_DECODE || mode == AUDIO_CODEC_MODE_BOTH) {
|
||||
SetVolume(current_volume_);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Codec started successfully in mode %d", mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::StopCodec() {
|
||||
if (!is_initialized_) {
|
||||
ESP_LOGW(TAG, "AudioCodec not initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stopping codec");
|
||||
// 修复:直接使用audio_hal_codec_mode_t类型
|
||||
esp_err_t ret = audio_hal_ctrl_codec(board_handle_->audio_hal, (audio_hal_codec_mode_t)current_mode_, AUDIO_HAL_CTRL_STOP);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to stop codec: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::SetVolume(uint8_t volume) {
|
||||
if (!is_initialized_) {
|
||||
ESP_LOGE(TAG, "AudioCodec not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (volume > 100) {
|
||||
ESP_LOGW(TAG, "Volume %d exceeds maximum, setting to 100", volume);
|
||||
volume = 100;
|
||||
}
|
||||
|
||||
// 转换为HAL音量范围 (0-63)
|
||||
int hal_volume = (volume * 63) / 100;
|
||||
esp_err_t ret = audio_hal_set_volume(board_handle_->audio_hal, hal_volume);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set volume: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
current_volume_ = volume;
|
||||
ESP_LOGI(TAG, "Volume set to %d%% (HAL volume: %d)", volume, hal_volume);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::GetVolume(uint8_t* volume) {
|
||||
if (!volume) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*volume = current_volume_;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::SetAdcVolume(uint8_t volume) {
|
||||
if (!is_initialized_) {
|
||||
ESP_LOGE(TAG, "AudioCodec not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
|
||||
esp_err_t ret = audio_hal_set_volume(board_handle_->adc_hal, volume);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "ADC volume set to %d", volume);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
audio_board_handle_t AudioCodec::GetBoardHandle() {
|
||||
return board_handle_;
|
||||
}
|
||||
|
||||
bool AudioCodec::IsInitialized() {
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::Deinitialize() {
|
||||
if (!is_initialized_) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Deinitializing AudioCodec");
|
||||
|
||||
StopCodec();
|
||||
Cleanup();
|
||||
|
||||
is_initialized_ = false;
|
||||
ESP_LOGI(TAG, "AudioCodec deinitialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void AudioCodec::Cleanup() {
|
||||
if (board_handle_) {
|
||||
audio_board_deinit(board_handle_);
|
||||
board_handle_ = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef AUDIO_CODEC_H
|
||||
#define AUDIO_CODEC_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "audio_hal.h"
|
||||
#include "board.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 使用audio_hal中已定义的模式类型,避免重复定义
|
||||
typedef audio_hal_codec_mode_t audio_codec_mode_t;
|
||||
|
||||
// 为了代码可读性,定义别名
|
||||
#define AUDIO_CODEC_MODE_DECODE AUDIO_HAL_CODEC_MODE_DECODE
|
||||
#define AUDIO_CODEC_MODE_ENCODE AUDIO_HAL_CODEC_MODE_ENCODE
|
||||
#define AUDIO_CODEC_MODE_BOTH AUDIO_HAL_CODEC_MODE_BOTH
|
||||
|
||||
class AudioCodec {
|
||||
public:
|
||||
// 获取单例实例
|
||||
static AudioCodec* GetInstance();
|
||||
|
||||
// 初始化音频编解码器(默认启用双向模式)
|
||||
esp_err_t Initialize();
|
||||
|
||||
// 音量控制
|
||||
esp_err_t SetVolume(uint8_t volume);
|
||||
esp_err_t GetVolume(uint8_t* volume);
|
||||
|
||||
// ADC音量控制(录音)
|
||||
esp_err_t SetAdcVolume(uint8_t volume);
|
||||
|
||||
// 获取音频板句柄
|
||||
audio_board_handle_t GetBoardHandle();
|
||||
|
||||
// 检查是否已初始化
|
||||
bool IsInitialized();
|
||||
|
||||
// 反初始化
|
||||
esp_err_t Deinitialize();
|
||||
|
||||
private:
|
||||
AudioCodec(); // 私有构造函数
|
||||
~AudioCodec();
|
||||
|
||||
// 禁止拷贝构造和赋值
|
||||
AudioCodec(const AudioCodec&) = delete;
|
||||
AudioCodec& operator=(const AudioCodec&) = delete;
|
||||
|
||||
static AudioCodec* instance_;
|
||||
static SemaphoreHandle_t mutex_;
|
||||
|
||||
audio_board_handle_t board_handle_;
|
||||
bool is_initialized_;
|
||||
audio_codec_mode_t current_mode_;
|
||||
uint8_t current_volume_;
|
||||
|
||||
esp_err_t InitializeBoard();
|
||||
void Cleanup();
|
||||
esp_err_t StartCodec(audio_codec_mode_t mode);
|
||||
esp_err_t StopCodec();
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AUDIO_CODEC_H
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/04_hal/audio_codec/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_HAL_AUDIO_CODEC AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] audio_codec module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"04_hal/audio_codec/audio_codec.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"04_hal/audio_codec"
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Base Board Hardware Abstraction Layer
|
||||
* Abstracts the communication transport (UART vs I2C) and sensor reading.
|
||||
*/
|
||||
class BaseBoardHal
|
||||
{
|
||||
public:
|
||||
virtual ~BaseBoardHal() = default;
|
||||
|
||||
/**
|
||||
* @brief Initialize the hardware interface
|
||||
*/
|
||||
virtual esp_err_t Init() = 0;
|
||||
|
||||
/**
|
||||
* @brief Send raw data to the base board
|
||||
* @param data Pointer to data buffer
|
||||
* @param len Length of data
|
||||
*/
|
||||
virtual esp_err_t Send(const uint8_t *data, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* @brief Read raw data from the base board
|
||||
* @param data Pointer to data buffer
|
||||
* @param len Length of data to read
|
||||
*/
|
||||
virtual esp_err_t Read(uint8_t *data, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the current angle from Hall sensor (or via query)
|
||||
* @param[out] angle Output angle in degrees (0.0 - 360.0)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t GetAngle(float *angle) = 0;
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_board_hal.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
class BaseBoardHalI2c : public BaseBoardHal
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kBaseSlaveAddr = 0x22;
|
||||
// TMAG5273 default address often 0x35 or defined by config
|
||||
static constexpr uint8_t kHallSensorAddr = 0x35;
|
||||
|
||||
BaseBoardHalI2c(i2c_bus_handle_t bus_handle)
|
||||
: bus_handle_(bus_handle) {}
|
||||
|
||||
virtual ~BaseBoardHalI2c()
|
||||
{
|
||||
// i2c_bus handles device management internally if used via i2c_bus_create
|
||||
// But here we just use the bus handle directly.
|
||||
}
|
||||
|
||||
virtual esp_err_t Init() override
|
||||
{
|
||||
if (!bus_handle_) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
// Check if device is alive
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, kBaseSlaveAddr << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW("BaseBoardHalI2c", "Base board not found at 0x%02X", kBaseSlaveAddr);
|
||||
// Don't fail init, maybe it's sleeping
|
||||
} else {
|
||||
ESP_LOGI("BaseBoardHalI2c", "Base board found at 0x%02X", kBaseSlaveAddr);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
virtual esp_err_t Send(const uint8_t *data, size_t len) override
|
||||
{
|
||||
if (!bus_handle_) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
// i2c_bus_write_bytes expects: bus, addr, reg_addr, reg_len, data, datalen
|
||||
// The data pointer in i2c_bus_write_bytes is (uint8_t *), not (const uint8_t *)
|
||||
// This is a common issue in legacy C APIs. We have to cast away constness.
|
||||
|
||||
return i2c_bus_write_bytes(bus_handle_, kBaseSlaveAddr << 1, NULL, 0, (uint8_t*)data, len);
|
||||
}
|
||||
|
||||
virtual esp_err_t Read(uint8_t *data, size_t len) override
|
||||
{
|
||||
if (!bus_handle_) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
return i2c_bus_read_bytes(bus_handle_, kBaseSlaveAddr << 1, NULL, 0, data, len);
|
||||
}
|
||||
|
||||
virtual esp_err_t GetAngle(float *angle) override
|
||||
{
|
||||
// TODO: Implement TMAG5273 read logic using i2c_bus_read_bytes
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_;
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_board_hal.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
class BaseBoardHalUart : public BaseBoardHal
|
||||
{
|
||||
public:
|
||||
BaseBoardHalUart(uart_port_t port) : port_(port) {}
|
||||
virtual ~BaseBoardHalUart() = default;
|
||||
|
||||
virtual esp_err_t Init() override
|
||||
{
|
||||
// Assuming UART is already initialized by board.cc or similar
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
virtual esp_err_t Send(const uint8_t *data, size_t len) override
|
||||
{
|
||||
if (port_ >= UART_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
int written = uart_write_bytes(port_, (const char *)data, len);
|
||||
return (written == (int)len) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
virtual esp_err_t Read(uint8_t *data, size_t len) override
|
||||
{
|
||||
if (port_ >= UART_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
int read = uart_read_bytes(port_, data, len, pdMS_TO_TICKS(100));
|
||||
return (read == (int)len) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
virtual esp_err_t GetAngle(float *angle) override
|
||||
{
|
||||
// TODO: Implement angle reading via UART (query command or report parsing)
|
||||
// For now, return not supported or cached value if we had one
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
private:
|
||||
uart_port_t port_;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
# main/04_hal/base_board_hal/module.cmake
|
||||
|
||||
# 注意:此文件夹可能没有 cpp 源文件,仅有头文件。如果有源文件,请追加到 MODULE_SRCS。
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_HAL_BASE_BOARD_HAL AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] base_board_hal module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"04_hal/base_board_hal"
|
||||
)
|
||||
@@ -0,0 +1,213 @@
|
||||
#include "aw8646.h"
|
||||
#include "config.h"
|
||||
#include "esp_log.h"
|
||||
#include "io_expansion_board.h"
|
||||
|
||||
// Define AW8646 specific pins for Board v1.1.16
|
||||
// P0_0 -> DRV_T0
|
||||
// P0_6 -> DRV_T1
|
||||
// Only if NFC_RST_PIN is defined (implying it's moved to GPIO, freeing up P0_0)
|
||||
#ifdef NFC_RST_PIN
|
||||
#define AW8646_USE_CURRENT_CONTROL
|
||||
#define AW8646_T0_PIN 0
|
||||
#define AW8646_T0_PORT OUTPUT_PORT0
|
||||
#define AW8646_T1_PIN 6
|
||||
#define AW8646_T1_PORT OUTPUT_PORT0
|
||||
#endif
|
||||
|
||||
Aw8646Driver::Aw8646Driver(IOExpansionBoard &ioExp) : io_expansion_(ioExp)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::Init()
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1. 默认处于休眠和禁用状态,防止发热!
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_SLEEP,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set sleep mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 2. Disable Enable Pin (High = Disable for AW8646)
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
true, // High -> Disable
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set enable mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef AW8646_USE_CURRENT_CONTROL
|
||||
// 3. Initialize T0 and T1 pins for Current Control
|
||||
// Default to Low (0, 0) for now.
|
||||
uint8_t output0_val = 0;
|
||||
err = io_expansion_.IoexpandReadReg(OUTPUT_PORT0, &output0_val);
|
||||
if (err == ESP_OK) {
|
||||
output0_val &= ~(1 << AW8646_T0_PIN); // Set T0 Low
|
||||
output0_val &= ~(1 << AW8646_T1_PIN); // Set T1 Low
|
||||
err = io_expansion_.IoexpandWriteReg(OUTPUT_PORT0, output0_val);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set T0/T1: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to read port 0: 0x%x", err);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 4. Set Microsteps (Default to 1/8 step)
|
||||
err = SetMicrosteps(8);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set microsteps: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 5. Set Default Direction
|
||||
err = SetDirection(true);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set direction: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "AW8646 Driver Initialized (EN Logic Inverted, T0/T1 Configured)");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::Enable(bool enable)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (enable)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enabling AW8646 (sleep + enable=Low)");
|
||||
|
||||
// Ensure Sleep is High (Work)
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Enable Pin: Low to Enable
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
false, // Low -> Enable
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "Disabling AW8646 (disable=High + sleep)");
|
||||
|
||||
// Enable Pin: High to Disable
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
true, // High -> Disable
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Sleep Pin: Low to Sleep
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_SLEEP,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::SetDirection(bool dir)
|
||||
{
|
||||
uint8_t mode = dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT;
|
||||
|
||||
return io_expansion_.StepperMotorSetDir(
|
||||
mode,
|
||||
STEPPER_MOTOR_DIR_PORT,
|
||||
STEPPER_MOTOR_DIR_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::Sleep(bool sleep)
|
||||
{
|
||||
uint8_t mode = sleep ? STEPPER_MOTOR_SLEEP : STEPPER_MOTOR_WORK;
|
||||
return io_expansion_.SetMotorSleepMode(
|
||||
mode,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::SetTriLevelPin(uint8_t port_reg, uint8_t config_reg, uint8_t pin, int state)
|
||||
{
|
||||
uint8_t val;
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
if (state == 2) { // Hi-Z -> Input
|
||||
// Set as Input
|
||||
err = io_expansion_.IoexpandReadReg(config_reg, &val);
|
||||
if (err != ESP_OK) return err;
|
||||
val |= (1 << pin); // Set Input
|
||||
err = io_expansion_.IoexpandWriteReg(config_reg, val);
|
||||
} else { // 0 or 1 -> Output
|
||||
// Set as Output
|
||||
err = io_expansion_.IoexpandReadReg(config_reg, &val);
|
||||
if (err != ESP_OK) return err;
|
||||
val &= ~(1 << pin); // Set Output
|
||||
err = io_expansion_.IoexpandWriteReg(config_reg, val);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Set Level
|
||||
err = io_expansion_.IoexpandReadReg(port_reg, &val);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
if (state == 1) val |= (1 << pin);
|
||||
else val &= ~(1 << pin);
|
||||
|
||||
err = io_expansion_.IoexpandWriteReg(port_reg, val);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::SetMicrosteps(int microsteps)
|
||||
{
|
||||
// AW8646 Microstep Table (Rising Edge Only)
|
||||
// 1 (Full): MODE1=0, MODE0=0
|
||||
// 2 (1/2): MODE1=0, MODE0=Z (Hi-Z)
|
||||
// 4 (1/4): MODE1=0, MODE0=1
|
||||
// 8 (1/8): MODE1=Z, MODE0=0
|
||||
// 16 (1/16): MODE1=Z, MODE0=1
|
||||
// 32 (1/32): MODE1=1, MODE0=Z
|
||||
|
||||
int m1 = 0;
|
||||
int m0 = 0;
|
||||
|
||||
switch(microsteps) {
|
||||
case 1: m1 = 0; m0 = 0; break;
|
||||
case 2: m1 = 0; m0 = 2; break; // Z
|
||||
case 4: m1 = 0; m0 = 1; break;
|
||||
case 8: m1 = 2; m0 = 0; break; // Z
|
||||
case 16: m1 = 2; m0 = 1; break; // Z
|
||||
case 32: m1 = 1; m0 = 2; break; // Z
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unsupported microsteps: %d, defaulting to 1/8", microsteps);
|
||||
m1 = 2; m0 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Setting Microsteps to 1/%d (M1=%d, M0=%d)", microsteps, m1, m0);
|
||||
|
||||
esp_err_t err;
|
||||
err = SetTriLevelPin(STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_CONFIG, STEPPER_MOTOR_M1_PIN, m1);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
err = SetTriLevelPin(STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_CONFIG, STEPPER_MOTOR_M0_PIN, m0);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef AW8646_DRIVER_H
|
||||
#define AW8646_DRIVER_H
|
||||
|
||||
#include "stepper_driver.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
class Aw8646Driver : public StepperDriver
|
||||
{
|
||||
public:
|
||||
explicit Aw8646Driver(IOExpansionBoard &ioExp);
|
||||
virtual ~Aw8646Driver() = default;
|
||||
|
||||
esp_err_t Init() override;
|
||||
esp_err_t Enable(bool enable) override;
|
||||
esp_err_t SetDirection(bool dir) override;
|
||||
esp_err_t Sleep(bool sleep) override;
|
||||
esp_err_t SetMicrosteps(int microsteps) override;
|
||||
|
||||
private:
|
||||
esp_err_t SetTriLevelPin(uint8_t port_reg, uint8_t config_reg, uint8_t pin, int state);
|
||||
|
||||
IOExpansionBoard &io_expansion_;
|
||||
const char* TAG = "Aw8646Driver";
|
||||
};
|
||||
|
||||
#endif // AW8646_DRIVER_H
|
||||
Binary file not shown.
@@ -0,0 +1,147 @@
|
||||
#include "drv8428.h"
|
||||
#include "config.h"
|
||||
|
||||
Drv8428Driver::Drv8428Driver(IOExpansionBoard &ioExp) : io_expansion_(ioExp)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::Init()
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1. Set Sleep Mode to WORK (wake up initially to configure?)
|
||||
// Actually BoardSweekar::StepperMotorInit sets it to WORK then ENABLE_DISABLE.
|
||||
// Let's follow that.
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set sleep mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 2. Disable Enable Pin
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_DISABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set enable mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 3. Set Microsteps (Defaulting to 1/8 as per original code which passed 4? need to verify)
|
||||
// BoardSweekar passed 4.
|
||||
// "io_expansion_.SetStepperMicrostepMode(4, ...)"
|
||||
// Let's assume 4 maps to 1/8 or whatever.
|
||||
err = SetMicrosteps(4);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set microsteps: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 4. Set Default Direction
|
||||
err = SetDirection(true); // Default to "UP" or whatever true means
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set direction: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "DRV8428 Driver Initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::Enable(bool enable)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (enable)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enabling stepper motor (sleep + enable)");
|
||||
|
||||
// 1. Set sleep mode to WORK
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 2. Set enable mode to ENABLE
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_ENABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "Disabling stepper motor (disable + sleep)");
|
||||
|
||||
// 1. Disable enable pin
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_DISABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 2. Set sleep mode to SLEEP
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_SLEEP,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::SetDirection(bool dir)
|
||||
{
|
||||
// dir: true=UP, false=DOWN (based on original StepperMotor::SetDir logic)
|
||||
// Original: dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT
|
||||
// Wait, StepperMotor::SetDir used STEPPER_MOTOR_RIGHT for true.
|
||||
// STEPPER_MOTOR_RIGHT is a macro, likely 1 or 0.
|
||||
|
||||
uint8_t mode = dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT;
|
||||
|
||||
return io_expansion_.StepperMotorSetDir(
|
||||
mode,
|
||||
STEPPER_MOTOR_DIR_PORT,
|
||||
STEPPER_MOTOR_DIR_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::Sleep(bool sleep)
|
||||
{
|
||||
// This is explicitly setting sleep mode, might be redundant with Enable(false)
|
||||
// but useful if we want to sleep without disabling or vice versa if supported.
|
||||
// For DRV8428, Enable(false) sets Sleep to SLEEP.
|
||||
|
||||
uint8_t mode = sleep ? STEPPER_MOTOR_SLEEP : STEPPER_MOTOR_WORK;
|
||||
return io_expansion_.SetMotorSleepMode(
|
||||
mode,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::SetMicrosteps(int microsteps)
|
||||
{
|
||||
// Original code used hardcoded ports for microsteps.
|
||||
// io_expansion_.SetStepperMicrostepMode(4, STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_PIN,
|
||||
// STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_PIN);
|
||||
|
||||
// We can just pass the value 'microsteps' if it corresponds to the index expected by SetStepperMicrostepMode.
|
||||
// Or we might need a mapping.
|
||||
// Assuming 'microsteps' passed here is the raw value/index for now.
|
||||
|
||||
io_expansion_.SetStepperMicrostepMode(
|
||||
(uint8_t)microsteps,
|
||||
STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_PIN,
|
||||
STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_PIN
|
||||
);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef DRV8428_DRIVER_H
|
||||
#define DRV8428_DRIVER_H
|
||||
|
||||
#include "stepper_driver.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
class Drv8428Driver : public StepperDriver
|
||||
{
|
||||
public:
|
||||
explicit Drv8428Driver(IOExpansionBoard &ioExp);
|
||||
virtual ~Drv8428Driver() = default;
|
||||
|
||||
esp_err_t Init() override;
|
||||
esp_err_t Enable(bool enable) override;
|
||||
esp_err_t SetDirection(bool dir) override;
|
||||
esp_err_t Sleep(bool sleep) override;
|
||||
esp_err_t SetMicrosteps(int microsteps) override;
|
||||
|
||||
private:
|
||||
IOExpansionBoard &io_expansion_;
|
||||
const char* TAG = "Drv8428Driver";
|
||||
};
|
||||
|
||||
#endif // DRV8428_DRIVER_H
|
||||
@@ -0,0 +1,17 @@
|
||||
# main/04_hal/stepper_driver/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_HAL_STEPPER_DRIVER AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] stepper_driver module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"04_hal/stepper_driver/drv8428.cc"
|
||||
"04_hal/stepper_driver/aw8646.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"04_hal/stepper_driver"
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef STEPPER_DRIVER_H
|
||||
#define STEPPER_DRIVER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Abstract base class for stepper motor driver chips.
|
||||
*
|
||||
* This interface abstracts the low-level control of the stepper motor driver,
|
||||
* such as enabling/disabling, setting direction, sleep mode, and microstepping configuration.
|
||||
* It does NOT handle step generation (that is handled by the StepperMotor class using GPTimer).
|
||||
*/
|
||||
class StepperDriver
|
||||
{
|
||||
public:
|
||||
virtual ~StepperDriver() = default;
|
||||
|
||||
/**
|
||||
* @brief Initialize the driver hardware (GPIOs, IO Expander, etc.)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t Init() = 0;
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the motor driver output.
|
||||
* @param enable true to enable, false to disable
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t Enable(bool enable) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the motor direction.
|
||||
* @param dir true for one direction (e.g. UP/CW), false for the other (e.g. DOWN/CCW)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t SetDirection(bool dir) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the motor driver to sleep mode to save power.
|
||||
* @param sleep true to sleep, false to wake up
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t Sleep(bool sleep) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set microstepping mode.
|
||||
* @param microsteps Microstepping value (e.g., 1, 2, 4, 8, 16, 32, etc.)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t SetMicrosteps(int microsteps) = 0;
|
||||
};
|
||||
|
||||
#endif // STEPPER_DRIVER_H
|
||||
Reference in new issue
Block a user