diff --git a/.gitmodules b/.gitmodules index c787ea0..4d48f44 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "components/zprotocols/zcancmder"] path = components/zprotocols/zcancmder url = zwsd@192.168.1.3:zprotocols/zcancmder.git +[submodule "components/zprotocols/errorcode"] + path = components/zprotocols/errorcode + url = zwsd@192.168.1.3:zprotocols/errorcode.git diff --git a/components/errorcode/errorcode.hpp b/components/errorcode/errorcode.hpp index ae9ecb1..edd7387 100644 --- a/components/errorcode/errorcode.hpp +++ b/components/errorcode/errorcode.hpp @@ -1,76 +1 @@ -#pragma once - -namespace iflytop { -namespace err { -using namespace std; - -#define ERROR_CODE(errortype, suberrorcode) (errortype + suberrorcode) - -typedef enum { - ksucc = ERROR_CODE(0, 0), - kfail = ERROR_CODE(0, 1), - - /** - * @brief 通信错误 - */ - kce_overtime = ERROR_CODE(1000, 0), - kce_noack = ERROR_CODE(1000, 1), - kce_errorack = ERROR_CODE(1000, 2), - kce_device_offline = ERROR_CODE(1000, 3), - kce_parse_json_err = ERROR_CODE(1000, 4), - kce_subdevice_overtime = ERROR_CODE(1000, 5), - - /** - * @brief 数据库错误 - */ - kdbe_user_not_exist = ERROR_CODE(2000, 0), - kdbe_catch_exception = ERROR_CODE(2000, 1), - - /** - * @brief 硬件错误 - */ - kharde_unfound = ERROR_CODE(3000, 0), - /** - * @brief 程序运行错误 - */ - kre_catch_exception = ERROR_CODE(4000, 0), - /** - * @brief 应用交互基本错误 - */ - kinteraction_error_passwd_error = ERROR_CODE(5000, 0), // 密码错误 - kinteraction_error_user_not_exist = ERROR_CODE(5000, 1), // 用户不存在 - /** - * @brief 系统错误 - */ - ksys_error = ERROR_CODE(6000, 0), - ksys_create_file_error = ERROR_CODE(6000, 1), - ksys_create_dir_error = ERROR_CODE(6000, 2), - ksys_open_file_error = ERROR_CODE(6000, 3), - ksys_open_dir_error = ERROR_CODE(6000, 4), - ksys_read_file_error = ERROR_CODE(6000, 5), - ksys_write_file_error = ERROR_CODE(6000, 6), - ksys_close_file_error = ERROR_CODE(6000, 7), - ksys_close_dir_error = ERROR_CODE(6000, 8), - ksys_delete_file_error = ERROR_CODE(6000, 9), - ksys_delete_dir_error = ERROR_CODE(6000, 10), - ksys_copy_file_error = ERROR_CODE(6000, 11), - - /** - * @brief 通用,但未归类错误 - * 50000 - */ - - kcommon_error_device_not_zero = ERROR_CODE(50000, 0), // 设备未归零 - kcommon_error_over_temperature = ERROR_CODE(50000, 1), // 过温 - kcommon_error_over_voltage = ERROR_CODE(50000, 2), // 过压 - kcommon_error_param_out_of_range = ERROR_CODE(50000, 3), // 参数超出范围 - kcommon_error_not_found_zero_point = ERROR_CODE(50000, 4), // 未找到零点 - kcommon_error_not_found_x_zero_point = ERROR_CODE(50000, 5), // 未找到零点 - kcommon_error_not_found_y_zero_point = ERROR_CODE(50000, 6), // 未找到零点 - kcommon_error_x_leave_away_zero_point_fail = ERROR_CODE(50000, 7), // 离开零点失败 - kcommon_error_y_leave_away_zero_point_fail = ERROR_CODE(50000, 8), // 离开零点失败 - kcommon_error_operation_not_support = ERROR_CODE(50000, 9), // 操作不支持 - -} error_t; -} // namespace err -} // namespace iflytop \ No newline at end of file +#include "sdk\components\zprotocols\errorcode\errorcode.hpp" \ No newline at end of file diff --git a/components/pipette_module/pipette_ctrl_module.cpp b/components/pipette_module/pipette_ctrl_module.cpp new file mode 100644 index 0000000..494fdf3 --- /dev/null +++ b/components/pipette_module/pipette_ctrl_module.cpp @@ -0,0 +1,62 @@ +#include "pipette_ctrl_module.hpp" +using namespace iflytop; +using namespace std; +#define TAG "PipetteModule" +void PipetteModule::initialize(SMTP2 *smtp2, // + StepMotorCtrlModule *stepMotor) { + m_smtp2 = smtp2; + m_stepMotor = stepMotor; + m_thread.init("pipette", 1024); +} + +int32_t PipetteModule::enable(u8 enable) { // + m_stepMotor->enable(enable); +} +int32_t PipetteModule::stop(u8 stop_type) { + m_stepMotor->stop(0); + m_smtp2->stop(); +} + +int32_t PipetteModule::zero_pos_calibrate(function exec_complete_cb) { + /** + * @brief + */ + + m_thread.stop(); + m_thread.start([this, exec_complete_cb]() { + // 移液枪复位 + // 移液枪复位完成后,开始进行零点校准 + // m_stepMotor->move_to_zero_with_calibrate(); + }); +} +int32_t PipetteModule::reset_device(function exec_complete_cb) { + /** + * @brief + */ + + m_thread.stop(); + m_thread.start([this, exec_complete_cb]() { + action_cb_status_t report_status = {0}; + // 移液枪复位 + int ret = m_smtp2->init_device(); + if (ret != 0) { + ZLOGE(TAG, "init_device fail"); + report_status.exec_status = ret; + if (exec_complete_cb) exec_complete_cb(report_status); + } + + // 等待移液枪复位完成 + while (true && !m_thread.getExitFlag()) { + int32_t state = m_smtp2->getState(); + if (state == 0) { + break; + } + m_thread.sleep(1000); + ZLOGI(TAG, "Waiting for SMTP2 to complete the reset"); + } + + ZLOGI(TAG, "SMTP2 reset complete"); + + // 移液枪复位完成后,开始进行零点校准 + }); +} \ No newline at end of file diff --git a/components/pipette_module/pipette_ctrl_module.hpp b/components/pipette_module/pipette_ctrl_module.hpp new file mode 100644 index 0000000..b1282b0 --- /dev/null +++ b/components/pipette_module/pipette_ctrl_module.hpp @@ -0,0 +1,36 @@ +#pragma once +// +#include "sdk/os/zos.hpp" +#include "sdk\components\sensors\smtp2\smtp2.hpp" +#include "sdk\components\step_motor_ctrl_module\step_motor_ctrl_module.hpp" +#include "sdk\components\tmc\basic\tmc_ic_interface.hpp" +#include "sdk\components\zprotocols\zcancmder\api\i_pipette_module.hpp" +// #include "StepMotorCtrlModule" + +namespace iflytop { + +class PipetteModule : public I_PipetteModule { + public: + private: + bool m_module_enable = false; + SMTP2 *m_smtp2; + StepMotorCtrlModule *m_stepMotor; + + ZThread m_thread; + + public: + void initialize(SMTP2 *smtp2, StepMotorCtrlModule *stepMotor); + + virtual int32_t enable(u8 enable); + virtual int32_t stop(u8 stop_type); + + virtual int32_t zero_pos_calibrate(function exec_complete_cb); + virtual int32_t reset_device(function exec_complete_cb); + + virtual int32_t take_tip(int tipid, function exec_complete_cb); + virtual int32_t remove_tip(function exec_complete_cb); + // 取液(平台参数,试管参数, 取样体积,取样高度,摇匀次数,摇匀体积) + virtual int32_t take_and_split_liquid(u8 tube_id, s16 liquid_volume, s16 zhight, s16 abs_zhight, s16 shake_times, s16 shake_volume, // + function exec_complete_cb); +}; +} // namespace iflytop \ No newline at end of file diff --git a/components/sensors/smtp2/smtp2.cpp b/components/sensors/smtp2/smtp2.cpp new file mode 100644 index 0000000..bd1b08c --- /dev/null +++ b/components/sensors/smtp2/smtp2.cpp @@ -0,0 +1,335 @@ +#include "smtp2.hpp" + +#include +#include +#include + +#include "sdk\components\zprotocols\errorcode\errorcode.hpp" +using namespace iflytop; +#define TAG "SMTP2" + +#define OVERTIME 20 +#define DUMP_HEX 1 + +/** + * @brief 协议概述 + * 协议示例 + * /2A3000R\r + * /:命令开始 + * 2:设备ID + * A:命令,绝对移动 + * 3000:参数,移动到3000位置 + * R:执行命令 + * \r:命令结束 + * + * + * 1.命令的名称;命令区分大小写 + * 2.一个命令包含多个参数时候,通过逗号隔开 + * 3.命令后面没有跟参数则使用默认值 + * 4.多个命令可以拼接,例如:A3000A0R + * 5.一旦执行命令,泵就处于忙碌状态,且在命令完成之前不会接受除了查询类命令、终止命令[T]以外的新命令 + * + * + */ + +/** + * @brief + * + * 命令集 + * 命令名称 命令 + * 初始化 Z + * 泵运动 A + * 泵配置 L(设置加速和减速) v开始速度 V最高速度 S设置预定速度 c停止速度 K背隙增量 N选择增量模式 h设置泵电机保持电流 m设置泵电机运行电流 + * 执行命令 R + * 执行最后一个命令字符串 X + * 重复命令序列 G + * 标记重复序列开始 g + * 延迟命令执行 M + * 停止命令执行 H + * 设置 I/O1 输出 J + * 终止 T + * 清除命令缓冲区 C + * E弹出 Tip + * t,压力液面检测(pLLD),吸取或分配 + * ^ 电容式液面检测(cLLD) + * B,混合式液面检测 + * f开启或停止压力数据流 + * +继续传输压力数据 + *

设定压力传感器增益 + * r 复位 LLD 输出 + * *,实时温度补偿 + * q,操作验证 + * s在 EEPROM 中存储命令字符串 + * e 执行存储在 EEPROM 中的命令字符串 + * 链接 EEPROM 中存储的命令字符串 + * U设置泵常规配置(PAGE:52) + * u,设置泵高级配置 + * Q 查询泵状态 + * =查询命令缓冲区 + * &报告固件版本 + * ? 报告泵参数 + * + */ + +/** + * 错误码 + * 40h 60h @ ` 0 无错误 + * 41h 61h A a 1 初始化失败 + * 42h 62h B b 2 无效命令 + * 43h 63h C c 3 无效参数 + * 44h 64h D d 4 压力传感器故障 + * 45h 65h E e 5 超过压力 + * 46h 66h F f 6 LLD 错误 + * 47h 67h G g 7 设备未初始化 + * 48h 68h H h 8 Tip 弹出错误 + * 49h 69h I i 9 泵过载 + * 4Ah 6Ah J j 10 Tip 脱落 + * 4Bh 6Bh K k 11 CAN 总线故障 + * 4Ch 6Ch L l 12 无效校验和 + * 4Dh 6Dh M m 13 EEPROM 故障 + * 4Eh 6Eh N n 14 命令缓冲区为空 + * 4Fh 6Fh O o 15 命令溢出 + * 50h 70h P p 16 Tip 堵塞 + * 51h 71h Q q 17 吸入空气 + * 52h 72h R r 18 液体中有气泡/泡沫 + * 53h 73h S s 19 吸取/分配量不准确 + * + */ + +static int Get1fromfloat(const float& val) { + float temp1 = val; + int t1 = (uint32_t)(temp1 * 10) % 10; + if (t1 > 4) { + temp1 = (float)(uint32_t)(temp1 + 1); + } else { + temp1 = (float)((uint32_t)(temp1)); + } + return (int)temp1; +} +int SMTP2::init_device() { + ZLOGI(TAG, "init_device"); + return doaction(fmt("/1ZR\r")); +} +int SMTP2::put_tip() { + // ZLOGI(TAG, "put_tip:%s", "/1E1R"); + ZLOGI(TAG, "put_tip"); + return doaction(fmt("/1E1R\r")); +} +int SMTP2::move_to(int pos) { + ZLOGI(TAG, "move_to %d", pos); + return doaction(fmt("/1N%dA%dR\r", 0, pos)); +} +int SMTP2::move_to_ul(int ul) { + /** + * @brief 分辨率在0.319ul进行操作 + */ + ZLOGI(TAG, "move_to_ul %d", ul); + float stepNumfloat = ul / 0.319; + int stepNum = Get1fromfloat(stepNumfloat); + return doaction(fmt("/1N%dA%dR\r", 0, stepNum)); +} +int SMTP2::set_resolution(int resolution) { + ZLOGI(TAG, "set_resolution %d", resolution); + return doaction(fmt("/1N%dR\r", resolution)); +} +void SMTP2::stop() { + ZLOGI(TAG, "stop"); + doaction(fmt("/1T\r")); +} + +int SMTP2::read_capacitance_val(int& capval) { + size_t rxlen = 0; + int ret = sendcmd(fmt("/1?68\r"), m_rxbuf, sizeof(m_rxbuf), rxlen); + if (ret != 0) { + return -1; + } + iflytop::err::error_t ecode = read_ack_error_code(m_rxbuf, rxlen); + if (ecode != err::ksucc) { + return ecode; + } + + capval = read_ack_int_val(m_rxbuf, rxlen); + return err::ksucc; +} + +char* SMTP2::fmt(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vsprintf(txbuf, fmt, args); + va_end(args); + return txbuf; +} + +/** + * @brief Get the State object + * + * @param state + * @param error + * @return int + */ +int SMTP2::getState(bool& isbusy, err::error_t& error) { + size_t rxlen = 0; + sprintf(txbuf, "/1Q\r"); + int ret = sendcmd(txbuf, strlen(txbuf), m_rxbuf, sizeof(m_rxbuf), rxlen); + if (ret != 0) { + return -1; + } + uint8_t errorcode = (uint8_t)m_rxbuf[2]; + if (errorcode > '`') { + isbusy = false; + errorcode = errorcode - '`'; + } else if (errorcode > '@') { + isbusy = true; + errorcode = errorcode - '@'; + } + return 0; +} + +void SMTP2::initialize(UART_HandleTypeDef* uart, DMA_HandleTypeDef* hdma_rx, DMA_HandleTypeDef* hdma_tx) { + m_uart = uart; + m_hdma_rx = hdma_rx; + m_hdma_tx = hdma_tx; +} + +int32_t SMTP2::getState() { + bool isbusy = false; + err::error_t error = err::ksucc; + int ret = getState(isbusy, error); + if (ret == 0) { + if (isbusy) { + return err::kcommon_error_device_is_busy; + } + return error; + } + return err::kcommon_error_device_is_offline; +} + +/******************************************************************************* + * BASIC * + *******************************************************************************/ + +iflytop::err::error_t SMTP2::read_ack_error_code(char* rxbuf, size_t rxlen) { + if (rxlen < 3) { + return err::kcommon_error_device_is_offline; + } + uint8_t errorcode = (uint8_t)rxbuf[2]; + if (errorcode > '`') { + errorcode = errorcode - '`'; + } else if (errorcode > '@') { + errorcode = errorcode - '@'; + } + return (err::error_t)errorcode; +} + +int SMTP2::read_ack_int_val(char* rxbuf, size_t rxlen) { + if (rxlen < 3) { + ZLOGW(TAG, "read_ack_int_val rxlen < 3"); + return 0; + } + + memset(m_rxprocessbuf, 0, sizeof(m_rxprocessbuf)); + memcpy(m_rxprocessbuf, rxbuf, rxlen); + + for (size_t i = 0; i < rxlen; i++) { + if (m_rxprocessbuf[i] == '\r' || m_rxprocessbuf[i] == '\n' || m_rxprocessbuf[i] == 0x03) { + m_rxprocessbuf[i] = 0; + break; + } + } + + // "/0`3\r\n" + int intval = atoi(m_rxprocessbuf + 3); + return intval; +} + +int32_t SMTP2::doaction(char* cmd) { + // + size_t rxlen = 0; + size_t txlen = strlen(cmd); + cmd[txlen] = '\r'; + cmd[txlen + 1] = 0; + int ret = sendcmd(cmd, txlen + 1, m_rxbuf, sizeof(m_rxbuf), rxlen); + if (ret != 0) { + return -1; + } + + uint8_t state = (uint8_t)m_rxbuf[2]; + if (state > '`') { + state = state - '`'; + } else if (state > '@') { + state = state - '@'; + } + + if (state == 0) { + return 0; + } + return state + err::kSMTP2_NoError; +} +int SMTP2::sendcmd(const char* cmd, char* rxbuf, size_t rxbuflen, size_t& rxlen) { return sendcmd(cmd, strlen(cmd), rxbuf, rxbuflen, rxlen); } +int SMTP2::sendcmd(const char* cmd, size_t txlen, char* rxbuf, size_t rxbuflen, size_t& rxlen) { + if (!m_uart) return -1; + + int ret = 0; + //size_t rxlen = 0; + +#ifdef DUMP_HEX + printf("tx:%s\n", cmd); +#endif + + if (m_hdma_rx) + ret = sendcmd_dma(cmd, txlen, (char*)m_rxbuf, sizeof(m_rxbuf), rxlen); + else + ret = sendcmd_block(cmd, txlen, (char*)m_rxbuf, sizeof(m_rxbuf), rxlen); + +#ifdef DUMP_HEX + printf("rx:%s\n", m_rxbuf); +#endif + return 0; +} + +int SMTP2::sendcmd_dma(const char* cmd, size_t txlen, char* rxbuf, size_t rxbuflen, size_t& rxlen) { + memset(rxbuf, 0, rxbuflen); + HAL_UART_Transmit(m_uart, (uint8_t*)cmd, txlen, 1000); + + uint32_t enter_ticket = HAL_GetTick(); + HAL_UARTEx_ReceiveToIdle_DMA(m_uart, (uint8_t*)rxbuf, rxbuflen); + bool overtime_flag = false; + while (HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_RX || // + HAL_UART_GetState(m_uart) == HAL_UART_STATE_BUSY_TX_RX) { + osDelay(1); + if (zos_haspassedms(enter_ticket) > OVERTIME) { + ZLOGW(TAG, "sendcmd_dma overtime"); + overtime_flag = true; + break; + } + } + HAL_UART_DMAStop(m_uart); + if (overtime_flag) { + return -1; + } + rxlen = rxbuflen - __HAL_DMA_GET_COUNTER(m_hdma_rx); + return 0; +} +int SMTP2::sendcmd_block(const char* cmd, size_t txlen, char* rxbuf, size_t rxbuflen, size_t& rxlen) { + // m_huart->tx(cmd); + memset(rxbuf, 0, rxbuflen); + // printf("tx:%s\n", cmd); + HAL_UART_Transmit(m_uart, (uint8_t*)cmd, txlen, 1000); + + int rxnum = 0; + HAL_StatusTypeDef rxstatus = HAL_UART_Receive(m_uart, (uint8_t*)&rxbuf[0], 1, OVERTIME); + if (rxstatus != HAL_OK) { + rxlen = 0; + return -1; + } + rxnum++; + for (;; rxnum++) { + HAL_StatusTypeDef rxstatus = HAL_UART_Receive(m_uart, (uint8_t*)&rxbuf[rxnum], 1, 3); + if (rxstatus != HAL_OK) break; + if ('\n' == rxbuf[rxnum]) break; + if (rxnum >= rxbuflen - 2) break; + } + // printf("SMTP2:m_rxbuf:(%d) %s\n", rxnum, rxbuf); + rxlen = rxnum; + return 0; +} diff --git a/components/sensors/smtp2/smtp2.hpp b/components/sensors/smtp2/smtp2.hpp new file mode 100644 index 0000000..8c4f2e9 --- /dev/null +++ b/components/sensors/smtp2/smtp2.hpp @@ -0,0 +1,141 @@ +#pragma once +#include "sdk\components\zprotocols\errorcode\errorcode.hpp" +#include "sdk\os\zos.hpp" +namespace iflytop { +using namespace std; + +class SMTP2 { + public: +#if 0 + typedef enum { + kNoError = 0, // 无错误 + kInitFail = 1, // 初始化失败 + kInvalidCmd = 2, // 无效命令 + kInvalidArg = 3, // 无效参数 + kPressureSensorError = 4, // 压力传感器故障 + kOverPressure = 5, // 超过压力 + kLLDError = 6, // LLD 错误 + kDeviceNotInit = 7, // 设备未初始化 + kTipPopError = 8, // Tip 弹出错误 + kPumpOverload = 9, // 泵过载 + kTipDrop = 10, // Tip 脱落 + kCanBusError = 11, // CAN 总线故障 + kInvalidChecksum = 12, // 无效校验和 + kEEPROMError = 13, // EEPROM 故障 + kCmdBufferEmpty = 14, // 命令缓冲区为空 + kCmdBufferOverflow = 15, // 命令溢出 + kTipBlock = 16, // Tip 堵塞 + kAirSuction = 17, // 吸入空气 + kBubble = 18, // 液体中有气泡/泡沫 + kVolumeError = 19, // 吸取/分配量不准确 + } error_t; +#endif + + + +#if 0 + typedef enum { + kIdle = 0, + kBusy = 1, + } state_t; +#endif + + private: + UART_HandleTypeDef* m_uart = nullptr; + uint8_t m_id = 0; + // const char* m_name = nullptr; + + + DMA_HandleTypeDef* m_hdma_rx; + DMA_HandleTypeDef* m_hdma_tx; + + char m_rxbuf[20] = {0}; + char m_rxprocessbuf[20] = {0}; + char txbuf[20]; + + int32_t nowpos = 0; + + public: + void initialize(UART_HandleTypeDef* uart, DMA_HandleTypeDef* hdma_rx, DMA_HandleTypeDef* hdma_tx); + /** + * @brief 获取当前设备状态 + * + * @return int32_t 返回iflytop::err + */ + int32_t getState(); + + /** + * @brief 设备初始化 + * + * @return int + */ + int init_device(); + /** + * @brief 放Tip + * + * @return int + */ + int put_tip(); + + /** + * @brief 移动到指定位置 + * + * @param pos + * @return int + */ + int move_to(int pos); + /** + * @brief 移动到指定位置 + * + * @param ul + * @return int + */ + int move_to_ul(int ul); + + /** + * @brief 读取电容值 + * + * @return int (0->159),接触到水后数值会变成159 + */ + int read_capacitance_val(int& capval); + /** + * @brief 设置分辨率 + * + * @param resolution + * 0:0.319ul + * 1:0.0199ul + * 2:nl + * @return int + */ + int set_resolution(int resolution); + + /** + * @brief Get the State object + * + * @param isbusy + * @param error + * @return int + */ + int getState(bool& isbusy, iflytop::err::error_t& error); + /** + * @brief + */ + void stop(); + + private: + int32_t doaction(char* cmd); + + int sendcmd(const char* cmd, char* rxbuf, size_t rxbuflen, size_t& rxlen); + int sendcmd(const char* cmd, size_t txlen, char* rxbuf, size_t rxbuflen, size_t& rxlen); + int sendcmd_dma(const char* cmd, size_t txlen, char* rxbuf, size_t rxbuflen, size_t& rxlen); + int sendcmd_block(const char* cmd, size_t txlen, char* rxbuf, size_t rxbuflen, size_t& rxlen); + + iflytop::err::error_t read_ack_error_code(char* rxbuf, size_t rxlen); + int read_ack_int_val(char* rxbuf, size_t rxlen); + + char* fmt(const char* fmt, ...); + + private: +}; + +} // namespace iflytop diff --git a/components/tmc/ic/ztmc4361A.cpp b/components/tmc/ic/ztmc4361A.cpp index 04a6550..bdcb743 100644 --- a/components/tmc/ic/ztmc4361A.cpp +++ b/components/tmc/ic/ztmc4361A.cpp @@ -347,9 +347,7 @@ void TMC4361A::driverIC_writeDatagram(uint8_t address, uint8_t x1, uint8_t x2, u uint8_t data[5] = {static_cast(address | static_cast(TMC2160_WRITE_BIT)), x1, x2, x3, x4}; readWriteCover(&data[0], 5); } -void TMC4361A::driverIC_writeInt(uint8_t address, int32_t value) { - driverIC_writeDatagram(address, BYTE(value, 3), BYTE(value, 2), BYTE(value, 1), BYTE(value, 0)); -} +void TMC4361A::driverIC_writeInt(uint8_t address, int32_t value) { driverIC_writeDatagram(address, BYTE(value, 3), BYTE(value, 2), BYTE(value, 1), BYTE(value, 0)); } int32_t TMC4361A::driverIC_readInt(uint8_t address) { address = TMC_ADDRESS(address); // register not readable -> shadow register copy @@ -375,8 +373,18 @@ uint32_t TMC4361A::driverIC_readICVersion() { int32_t value = driverIC_readInt(TMC2160_IOIN___OUTPUT); return (value & TMC2160_VERSION_MASK) >> TMC2160_VERSION_SHIFT; } -void TMC4361A::driverIC_setIHOLD_IRUN(uint8_t ihold, uint8_t irun, uint16_t iholddelay) { - driverIC_writeInt(TMC2160_IHOLD_IRUN, (iholddelay << TMC2160_IHOLDDELAY_SHIFT) | (irun << TMC2160_IRUN_SHIFT) | (ihold << TMC2160_IHOLD_SHIFT)); +void TMC4361A::driverIC_setIHOLD_IRUN(uint8_t ihold, uint8_t irun, uint16_t iholddelay) { driverIC_writeInt(TMC2160_IHOLD_IRUN, (iholddelay << TMC2160_IHOLDDELAY_SHIFT) | (irun << TMC2160_IRUN_SHIFT) | (ihold << TMC2160_IHOLD_SHIFT)); } + +// Left Virtual Limit Switch XACTUAL ≤ VIRT_STOP_LEFT 时触发 +void TMC4361A::setLeftVirtualLimitSwitch(bool enable, int32_t position) { + PRV_FIELD_WRITE(TMC4361A_REFERENCE_CONF, TMC4361A_VIRTUAL_LEFT_LIMIT_EN_MASK, TMC4361A_VIRTUAL_LEFT_LIMIT_EN_SHIFT, enable ? 1 : 0); + writeInt(TMC4361A_VIRT_STOP_LEFT, position); +} + +// Right Virtual Limit Switch XACTUAL ≥ VIRT_STOP_RIGHT 时触发 +void TMC4361A::setRightVirtualLimitSwitch(bool enable, int32_t position) { + PRV_FIELD_WRITE(TMC4361A_REFERENCE_CONF, TMC4361A_VIRTUAL_RIGHT_LIMIT_EN_MASK, TMC4361A_VIRTUAL_RIGHT_LIMIT_EN_SHIFT, enable ? 1 : 0); + writeInt(TMC4361A_VIRT_STOP_RIGHT, position); } #endif diff --git a/components/tmc/ic/ztmc4361A.hpp b/components/tmc/ic/ztmc4361A.hpp index e0b115e..c280371 100644 --- a/components/tmc/ic/ztmc4361A.hpp +++ b/components/tmc/ic/ztmc4361A.hpp @@ -118,6 +118,12 @@ class TMC4361A : public IStepperMotor { virtual void setScale(float scale); + // Left Virtual Limit Switch XACTUAL ≤ VIRT_STOP_LEFT 时触发 + void setLeftVirtualLimitSwitch(bool enable, int32_t position); + + // Right Virtual Limit Switch XACTUAL ≥ VIRT_STOP_RIGHT 时触发 + void setRightVirtualLimitSwitch(bool enable, int32_t position); + /******************************************************************************* * 驱动器初始化方法 * *******************************************************************************/ diff --git a/components/zprotocols/errorcode b/components/zprotocols/errorcode new file mode 160000 index 0000000..072751f --- /dev/null +++ b/components/zprotocols/errorcode @@ -0,0 +1 @@ +Subproject commit 072751f7f4573591d229a337fb16181dd58aa7bc diff --git a/components/zprotocols/zcancmder b/components/zprotocols/zcancmder index 804b964..40bae4b 160000 --- a/components/zprotocols/zcancmder +++ b/components/zprotocols/zcancmder @@ -1 +1 @@ -Subproject commit 804b964be4e24a8fc929794768db6ffb5eeaa9a6 +Subproject commit 40bae4b887cc873eea0d37ba581669363fdc6f27