CW32 硬件除法器与 CORDIC 加速器使用指南
CW32L012 在芯源的 M0+ 产品线里算是一个“越级”的存在,它内置了两个硬件数学加速单元:EAU 和 CORDIC。EAU 负责除法、开方这类基础运算,CORDIC 专攻三角函数和向量旋转。这两个外设的存在,让一颗没有 FPU 的 M0+ 芯片在处理电机控制、信号处理任务时,不再被软件浮点库拖后腿。
先搞清楚它们各自管什么
EAU 的全称是扩展算术单元(Extended Arithmetic Unit),核心能力是硬件除法和开方。以往 M0+ 做一次 32 位除法要靠软件循环,几十个周期起步;EAU 把除法做成了硬件指令级操作,开方也一样。
CORDIC 是坐标旋转数字计算机算法(Coordinate Rotation Digital Computer)的硬件实现,本质是一堆加减法和移位操作的迭代,不需要乘法器。CW32L012 的 CORDIC 支持这些运算:余弦 cos、正弦 sin、相位角 atan2、模长 hypot、反正切 atan、双曲余弦 cosh、双曲正弦 sinh、双曲反正切 atanh,迭代次数可配置,范围 6 到 66。
两者的配合很自然。比如在 FOC 的 Park 变换里,你需要同时算一个向量的幅值和角度。坐标分量 x、y 送进 CORDIC,直接算出角度 θ=atan(y/x) 和平方和 x²+y²;然后把平方和丢给 EAU 开方,模长 r=√(x²+y²) 就出来了。实测误差在 1e-7 rad 量级,比调用 math.h 的软件实现快几十到上百倍。
CORDIC 怎么用
用 CORDIC 之前,先要理解定点数格式。CW32L012 的 CORDIC 支持 Q1.15 和 Q1.31 两种格式。Q1.15 是 16 位有符号数,1 位整数加 15 位小数,范围 [-1, 1);Q1.31 是 32 位,1 位整数加 31 位小数。换算关系很简单:sint16 的 Q1.15 值 = 实际值 × 2^15,sint32 的 Q1.31 值 = 实际值 × 2^31。
计算 sin 或 cos 的时候,角度也要转成定点格式。CORDIC 内部把整个圆周映射到 [-1, 1) 区间,所以角度参数是一个归一化值。45° 对应 0.25(即 1/4),30° 对应约 0.167(即 1/6)。写入这个值之前,按 Q1.31 格式乘上 2^31 再取整。
c
int32_t float_to_q1_31(float value) {
return (int32_t)round(value * 2147483648.0); // 2^31
}
// 计算 45° 的 sin/cos
int32_t angle = float_to_q1_31(0.25); // 45° = 1/4
启动运算的规则要看清楚。只有一个输入数据的时候(比如算 sin 或 cos,只需要角度),把数据写进对应的寄存器就自动启动。需要两个输入数据的时候(比如 atan2 需要 x 和 y),写 y 寄存器会启动运算。
运算状态通过 CORDIC_CSR.BUSY 位判断。BUSY 为 0 表示空闲或运算完成,可以读结果或开新一轮;BUSY 为 1 表示正在算,不能碰。完成标志是 CORDIC_CSR.EOC,但 EOC 被置位并不妨碍启动新一轮运算,新一轮启动时它会自动清零。
c
while (CORDIC_GetStatus().busy); // 等上一轮结束
CW_CORDIC->Z = angle; // 写入 Z 寄存器启动 cos 运算
while (CORDIC_GetStatus().busy); // 等本轮结束
int32_t cos_val = CW_CORDIC->X; // 读 X 得 cos
int32_t sin_val = CW_CORDIC->Y; // 读 Y 得 sin
迭代次数直接影响精度和耗时。官方建议 Q1.15 格式迭代 16 到 20 次,Q1.31 格式迭代 24 到 32 次。迭代次数越多,逼近误差越小,但运算时间线性增加。CORDIC 硬件一次迭代只要 1 到 2 个时钟周期,全流程算完大约 6 到 10µs,比软件实现快 30 到 40 倍。
一个容易踩的坑
读结果的时候,如果 Q1.15 格式下直接写 result & 0xFFFF 然后当正数用,负数的符号位会被抹掉,变成一个大正数。cos(π/4) 是正数没问题,但 cos(3π/4) 就会出错。更稳妥的写法是强制转成 int16_t 再参与运算。
还有伸缩因子补偿的问题。CORDIC 每旋转一次都会引入一个固定的增益 K,所有迭代完成后总增益约为 1.647。CW32L012 的 CORDIC 提供了硬件补偿选项,初始化时把 comp 位设为 1,硬件会自动抵消这个增益,你读到的就是归一化后的结果,不需要软件再除一遍。 |
|