Skip to content

中文 Readme

dukelec edited this page Jun 26, 2024 · 2 revisions

CDSTEP 简介

cdstep_v4

RS-485 插头型号: Molex 5264 (4 pin)

下载项目:

git clone --recurse-submodules https://github.com/dukelec/cdstep.git

工作框图

block_diagram

图形配置工具

CDBUS GUI Tool: https://github.com/dukelec/cdbus_gui

上电后,先往 state 写 1,然后往 tc_pos 写入目标位置 ,步进电机便会转动。

cdbus_gui

修改配置后,往 save_conf 写 1 保存配置到 flash。
如果需要恢复默认配置,修改 magic_code 为其它值,保存到 flash,然后重新上电即可。

调试打印窗口:

csa_list_show

波形窗口:

plot

波形细节、IAP 升级、数据导入导出(包含寄存器、log、波形):

iap_export

协议

CDSTEP 是一个开源步进电机控制器,它使用 RS485 接口,默认波特率为 115200 bps, 最高 > 10 Mbps,默认地址为 0xfe.

最底层协议为 CDBUS,其帧格式为:
src, dst, len, [payload], crc_l, crc_h

由 3 字节头、数据 和 最后 2 字节的 CRC 结尾(算法同 ModBus RTU 的 CRC)。
CDBUS 协议具体参见: https://cdbus.org

Payload 部分为 CDNET 协议,同时支持 CDNET L0 和 L1 两个版本。
CDNET 协议具体参见: https://github.com/dukelec/cdnet

CDNET 和 TCP/IP 中的 UDP 的概念比较类似,主要参考 UDP 的端口号的概念。
譬如最简单的 CDNET L0 协议,从主机默认端口发送一个字节数据 0x00 到 CDSTEP 的 1 号端口的格式:

01 00

第一个字节是目标端口号,然后跟数据即可。

以上示范,完整的 CDBUS 协议帧为(主机地址默认为 0,CDSTEP 为 0xfe):

00 fe 02  01 00  crc_l crc_h

以上示范,端口 1 是设备信息相关的,端口号可以看做 主命令号,首字节数据约定为 子命令号, 子命令号 0x00 是读设备信息。

CDSTEP 一共有 4 个端口接收指令,分別是:

端口 1: 设备信息

唯一一个子命令号 0 是用来查询信息。

返回 0x80 + 设备信息字符串,譬如 M: cdstep; S: 23ff7660d405535353733034; SW: v1.1.

端口 5: 参数表读写

参数表在代码中是 csa_t 类型的全局结构体,csa 为 Config Status Area 的缩写,它的前半部分可以写入 Flash 中,以保存一些用户设置, 上电时从 flash 中恢复 csa 的前半部分数据。而后部分数据为运行中的一些变量,通过此接口把这些变量暴露给用户,让用户直接读写可以大大简化代码。

不过,我们在读写前后,可以通过预先定义的 hook 钩子函数,对写入数据进行安全检查,或是定义写入后需要执行的动作。 而对于读取命令,可以提前为用户準备其所需要的数据格式,譬如格式转换。

另外,为了方便用户整体同步 csa 信息,我们定义了 csa 的哪些区域可写,不可写的区域用户不用小心避开,写入的数据直接会被忽略。

譬如,我们可以直接把 pid 对象放在 csa 表中,pid 对象中有一些是内部变量,不应该被用户修改, 有了可写区域限制,用户可以非常方便的整块写入数据,不用担心写到不该写的数据。

读写参数表的子命令为:

read:       0x00, offset_16, len_8   | return [0x80, data]
read_dft:   0x01, offset_16, len_8   | return [0x80, data]
write:      0x20, offset_16 + [data] | return [0x80] on success

譬如设置电机锁舵并进入位置模式。电机状态 state 值为 0 不锁舵,为 1 锁舵。

state 本身的地址是 0x00b8,长度 1 个字节,那么上电后需要锁舵,发送以下数据到端口 5 即可:

20  b8 00  01

20 是子命令 writeb8 00 是地址 0x00b8 的小端格式(除非特別说明,否则都是用小端),最后一个 01 是写入数值。

修改 csa_t 的定义,可能会影响到很多寄存器的地址,如果每次都是手工计算各寄存器的地址,很麻烦且容易出错,所以,我们通过 csa_list_show 这个函数, 上电时自动打印出所有寄存器的地址、类型,以及说明信息,可以直接拷贝到配置文档中。

每次修改 csa_t 的定义后,请同时修改其中的 conf_ver 版本号。

端口 6: 快速读写

位置模式常用的参数表项有:

tc_pos, type: int32_t
tc_speed, type: uint32_t
tc_accel, type: uint32_t

我们可以通过端口 5 来写这些数据,但是,有的时候我们还想去写非连续的其它 表项,这样就要拆分多条命令,效率低,且容易导致数据不同步。
而且,我们还想设备同时回覆电机的错误码和一些运行数据,但不同模式下我们关心的运行数据不尽相同,如果写死会比较不方便。

参数表项内有 快速读写 通道的配置:(qxchg 是 quick exchange 的缩写)

regr_t          qxchg_set[5];
regr_t          qxchg_ret[5];

以上数组,首个 size 值为 0 的元素表示它和后序的未使用,元素的定义:

typedef struct {
    uint16_t        offset;
    uint16_t        size;
} regr_t; // reg range

qxchg_setqxchg_ret 是 快速读写 的 子命令 20 所用, 预先设置好写哪些数据,以及返回哪些数据,然后发送 20 + 需要写的数据就可以了, 会返回 80 + 返回的数据。

qxchg_set 默认设定只用了一个元素,指向 tc_pos, tc_speedtc_accel 这 3 个表项所在的区域,
如果需要修改目标位置参数 tc_pos 为 0,向 端口 6 写数据 20 00 00 00 00 即可(20 是子命令号)。
如果需要同时修改目标位置和目标速度,譬如位置改为 0x00001000,速度改为 0x00000500,则写入 20 00 10 00 00 00 05 00 00.

子命令 2f 支持接收包含多个设备数据的广播或组播包。

端口 8: Flash 读写

可以通过此接口实现 IAP 升级。

子命令为:

erase:   0x2f, addr_32, len_32  | return [0x80] on success
write:   0x20, addr_32 + [data] | return [0x80] on success
read:    0x00, addr_32, len_8   | return [0x80, data]
cal crc: 0x10, addr_32, len_32  | return [0x80, crc_16] # modbus crc

先要把需要写的区域擦除,然后写入数据,最后调用 crc 计算所写数据是否正确即可。 也可以读回所有数据来判断,速度会稍慢一点。

Bootloader 上电后,先使用默认波特率 115200,如果收到主机设置 keep_in_bl 的命令就保持此波特率,如果一秒锺内没有收到该命令,则切换到 Flash 中保存的波特率继续等待命令,如果再过一秒依然没收到命令,则跳转执行 APP 固件。Bootloader 和 APP 共享 csa 配置的开头部分,其中包含了用户设置的波特率。

如果不知道 CDSTEP 当前的 ID 号,可以发送 info 命令到广播地址 0xff 进行搜寻。

当前 MCU Flash 总共 128K, 每页大小为 2K, 前 24K 存放 Bootloader,最后 2K 存放 csa 参数表,其余为 APP.

波形数据

和 快速读写 通道的 qxchg_XXX 数组一样,波形数据用同样的方式定义需要上报的数据的组成,可以自由配置想要观察的变量。 和 qxchg_XXX 不同的是,一个数据包会存放很多组数据,等数据包满到一定程度再发送给主机。

如果是固定周期的情况,譬如 FOC 电机,可以在电流环中为一个变量(譬如 loop_cnt)每次加 1,然后只需要把 loop_cnt 写在每个数据包的最前面即可。
但我们这个 stepper motor 控制,周期不固定,所以要把时间信息和其它被观察的变量,每次都一起记录。

使用 plot 调试时,建议把设备的波特率设置高一些。
如果数据量很大,CDSTEP 会把连续的信息保存在 buffer 中,buffer 满之后,会等待 buffer 完全清空再继续,能最大程度保证数据的连续性,避免细节丟失。