本帖最后由 zhanzr21 于 2019-9-7 16:06 编辑
软件-CORDIC数学和定点运算据我所知, G4系列应该是第一个配备CORDIC单元的STM32系列. CORDIC数学计算对于做过DSP的工程师应该不陌生, 但是对于大多数STM32开发者来讲应该是个模糊的概念. 这里简单介绍下. CORDIC在STM32G4上是个协处理器, 也可以叫做硬件加速单元. 它用坐标转换的方法来计算, 只能接受定点数, 目前支持的函数: Sine, Cosine,Sinh, Cosh, Atan, Atan2, Atanh, Modulus, Square root, Natural logarithm.内部精度为24bit,一般喂给它Q31.1的定点数,输出也是Q31.1,当然也可以喂给它Q15.1的定点数. 因为它的处理原理是加法+移位, 虽然动态范围比浮点运算小导致精度小, 但是运算起来比FPU做泰勒级数逼近要快很多.况且它是真正的协处理器, 可以跟DMA联合起来, 所以在精度牺牲一点的情况下比FPU计算要快,而且可以解放CPU做其他事情.所以在电机控制, 传感器数据前置处理的应用中这种运算用的很广泛. Q格式的定点数,如果使用过CMSIS DSP的程序员可能比较了解, 但是估计大多数程序员还是很陌生, 也介绍下. 简而言之, Q定点数, 就是用整型数来表示小数的一种方式. Q31.1使用32bit的整数来表示-1到1的区间,也有人用来表示0到2的区间, 内部原理是一致的. 大多数运算中, 采用-1到1的区间.Q格式与浮点数的转换方式: 将浮点数转换为q._n._t的格式: 1.浮点数乘以2的n次方 2.四舍五入
将q._n._t格式转换为浮点格式: 1.按照native的方式将浮点数转为定数(四舍五入) 2.将上一步结果除以2的n次方 关于转换,本人有个简单的Python脚本可以供参考. import os,sys,math
INT32_MAX = (1<<31)-1
UINT32_MAX = (1<<32)-1
ARRAY_SIZE = 64
TEST_CSV_FILE = "test_q.csv"
test_q_angle_cordic = [0x00000000, 0x04000000, 0x08000000, 0x0C000000,
0x10000000, 0x14000000, 0x18000000, 0x1C000000,
0x20000000, 0x24000000, 0x28000000, 0x2C000000,
0x30000000, 0x34000000, 0x38000000, 0x3C000000,
0x40000000, 0x44000000, 0x48000000, 0x4C000000,
0x50000000, 0x54000000, 0x58000000, 0x5C000000,
0x60000000, 0x64000000, 0x68000000, 0x6C000000,
0x70000000, 0x74000000, 0x78000000, 0x7C000000,
0x80000000, 0x84000000, 0x88000000, 0x8C000000,
0x90000000, 0x94000000, 0x98000000, 0x9C000000,
0xA0000000, 0xA4000000, 0xA8000000, 0xAC000000,
0xB0000000, 0xB4000000, 0xB8000000, 0xBC000000,
0xC0000000, 0xC4000000, 0xC8000000, 0xCC000000,
0xD0000000, 0xD4000000, 0xD8000000, 0xDC000000,
0xE0000000, 0xE4000000, 0xE8000000, 0xEC000000,
0xF0000000, 0xF4000000, 0xF8000000, 0xFC000000]
test_q_angle_cmsis_dsp = [ 0x00000000, 0x02000000, 0x04000000, 0x06000000,
0x08000000, 0x0A000000, 0x0C000000, 0x0E000000,
0x10000000, 0x12000000, 0x14000000, 0x16000000,
0x18000000, 0x1A000000, 0x1C000000, 0x1E000000,
0x20000000, 0x22000000, 0x24000000, 0x26000000,
0x28000000, 0x2A000000, 0x2C000000, 0x2E000000,
0x30000000, 0x32000000, 0x34000000, 0x36000000,
0x38000000, 0x3A000000, 0x3C000000, 0x3E000000,
0x40000000, 0x42000000, 0x44000000, 0x46000000,
0x48000000, 0x4A000000, 0x4C000000, 0x4E000000,
0x50000000, 0x52000000, 0x54000000, 0x56000000,
0x58000000, 0x5A000000, 0x5C000000, 0x5E000000,
0x60000000, 0x62000000, 0x64000000, 0x66000000,
0x68000000, 0x6A000000, 0x6C000000, 0x6E000000,
0x70000000, 0x72000000, 0x74000000, 0x76000000,
0x78000000, 0x7A000000, 0x7C000000, 0x7E000000]
test_q_ref_sin = [ 0x00000000, 0x0C8BD35E, 0x18F8B83C, 0x25280C5D,
0x30FBC54D, 0x3C56BA70, 0x471CECE6, 0x5133CC94,
0x5A827999, 0x62F201AC, 0x6A6D98A4, 0x70E2CBC6,
0x7641AF3C, 0x7A7D055B, 0x7D8A5F3F, 0x7F62368F,
0x80000000, 0x7F62368F, 0x7D8A5F3F, 0x7A7D055B,
0x7641AF3C, 0x70E2CBC6, 0x6A6D98A4, 0x62F201AC,
0x5A827999, 0x5133CC94, 0x471CECE6, 0x3C56BA70,
0x30FBC54D, 0x25280C5D, 0x18F8B83C, 0x0C8BD35E,
0x00000000, 0xF3742CA2, 0xE70747C4, 0xDAD7F3A3,
0xCF043AB3, 0xC3A94590, 0xB8E3131A, 0xAECC336C,
0xA57D8667, 0x9D0DFE54, 0x9592675C, 0x8F1D343A,
0x89BE50C4, 0x8582FAA5, 0x8275A0C1, 0x809DC971,
0x80000000, 0x809DC971, 0x8275A0C1, 0x8582FAA5,
0x89BE50C4, 0x8F1D343A, 0x9592675C, 0x9D0DFE54,
0xA57D8667, 0xAECC336C, 0xB8E3131A, 0xC3A94590,
0xCF043AB3, 0xDAD7F3A3, 0xE70747C4, 0xF3742CA2]
test_q_ref_cos = [ 0x80000000, 0x7F62368F, 0x7D8A5F3F, 0x7A7D055B,
0x7641AF3C, 0x70E2CBC6, 0x6A6D98A4, 0x62F201AC,
0x5A827999, 0x5133CC94, 0x471CECE6, 0x3C56BA70,
0x30FBC54D, 0x25280C5D, 0x18F8B83C, 0x0C8BD35E,
0x00000000, 0xF3742CA2, 0xE70747C4, 0xDAD7F3A3,
0xCF043AB3, 0xC3A94590, 0xB8E3131A, 0xAECC336C,
0xA57D8667, 0x9D0DFE54, 0x9592675C, 0x8F1D343A,
0x89BE50C4, 0x8582FAA5, 0x8275A0C1, 0x809DC971,
0x80000000, 0x809DC971, 0x8275A0C1, 0x8582FAA5,
0x89BE50C4, 0x8F1D343A, 0x9592675C, 0x9D0DFE54,
0xA57D8667, 0xAECC336C, 0xB8E3131A, 0xC3A94590,
0xCF043AB3, 0xDAD7F3A3, 0xE70747C4, 0xF3742CA2,
0x00000000, 0x0C8BD35E, 0x18F8B83C, 0x25280C5D,
0x30FBC54D, 0x3C56BA70, 0x471CECE6, 0x5133CC94,
0x5A827999, 0x62F201AC, 0x6A6D98A4, 0x70E2CBC6,
0x7641AF3C, 0x7A7D055B, 0x7D8A5F3F, 0x7F62368F]
test_q_cordic_result = [0x00000600, 0x7FFFFE00,
0x0C8BD600, 0x7F623100,
0x18F8B700, 0x7D8A5A00,
0x25280600, 0x7A7D0700,
0x30FBC900, 0x7641A800,
0x3C56B400, 0x70E2CA00,
0x471CEC00, 0x6A6D9900,
0x5133C500, 0x62F20400,
0x5A827600, 0x5A827900,
0x62F20600, 0x5133C300,
0x6A6D9900, 0x471CEC00,
0x70E2CA00, 0x3C56B400,
0x7641AC00, 0x30FBC300,
0x7A7D0700, 0x25280600,
0x7D8A5A00, 0x18F8B500,
0x7F623100, 0x0C8BD400,
0x7FFFFF00, 0xFFFFFF00,
0x7F623200, 0xF3742900,
0x7D8A5B00, 0xE7074A00,
0x7A7D0800, 0xDAD7F100,
0x7641A800, 0xCF043C00,
0x70E2CB00, 0xC3A94B00,
0x6A6D9900, 0xB8E31100,
0x62F20400, 0xAECC3200,
0x5A827A00, 0xA57D8500,
0x5133C400, 0x9D0E0300,
0x471CED00, 0x95926A00,
0x3C56B500, 0x8F1D3700,
0x30FBC400, 0x89BE5500,
0x25280500, 0x85830100,
0x18F8B400, 0x8275A400,
0x0C8BD300, 0x809DCF00,
0xFFFFFA00, 0x80000200,
0xF3742A00, 0x809DCF00,
0xE7074900, 0x8275A600,
0xDAD7FA00, 0x8582F900,
0xCF043700, 0x89BE5800,
0xC3A94C00, 0x8F1D3600,
0xB8E31400, 0x95926700,
0xAECC3B00, 0x9D0DFC00,
0xA57D8A00, 0xA57D8700,
0x9D0DFA00, 0xAECC3D00,
0x95926700, 0xB8E31400,
0x8F1D3600, 0xC3A94C00,
0x89BE5400, 0xCF043D00,
0x8582F900, 0xDAD7FA00,
0x8275A600, 0xE7074B00,
0x809DCF00, 0xF3742C00,
0x80000100, 0x00000100,
0x809DCE00, 0x0C8BD700,
0x8275A500, 0x18F8B600,
0x8582F800, 0x25280F00,
0x89BE5800, 0x30FBC400,
0x8F1D3500, 0x3C56B500,
0x95926700, 0x471CEF00,
0x9D0DFC00, 0x5133CE00,
0xA57D8600, 0x5A827B00,
0xAECC3C00, 0x62F1FD00,
0xB8E31300, 0x6A6D9600,
0xC3A94B00, 0x70E2C900,
0xCF043C00, 0x7641AB00,
0xDAD7FB00, 0x7A7CFF00,
0xE7074C00, 0x7D8A5C00,
0xF3742D00, 0x7F623100,]
test_q_cmsis_result = [0x00000000, 0x7FFFFFFE,
0x0C8BD35E, 0x7F62368E,
0x18F8B83C, 0x7D8A5F40,
0x25280C5E, 0x7A7D055A,
0x30FBC54C, 0x7641AF3C,
0x3C56BA70, 0x70E2CBC6,
0x471CECE6, 0x6A6D98A4,
0x5133CC94, 0x62F201AC,
0x5A82799A, 0x5A82799A,
0x62F201AC, 0x5133CC94,
0x6A6D98A4, 0x471CECE6,
0x70E2CBC6, 0x3C56BA70,
0x7641AF3C, 0x30FBC54C,
0x7A7D055A, 0x25280C5E,
0x7D8A5F40, 0x18F8B83C,
0x7F62368E, 0x0C8BD35E,
0x7FFFFFFE, 0x00000000,
0x7F62368E, 0xF3742CA2,
0x7D8A5F40, 0xE70747C4,
0x7A7D055A, 0xDAD7F3A2,
0x7641AF3C, 0xCF043AB2,
0x70E2CBC6, 0xC3A94590,
0x6A6D98A4, 0xB8E31318,
0x62F201AC, 0xAECC336C,
0x5A82799A, 0xA57D8666,
0x5133CC94, 0x9D0DFE54,
0x471CECE6, 0x9592675C,
0x3C56BA70, 0x8F1D343A,
0x30FBC54C, 0x89BE50C2,
0x25280C5E, 0x8582FAA4,
0x18F8B83C, 0x8275A0C0,
0x0C8BD35E, 0x809DC970,
0x00000000, 0x80000000,
0xF3742CA2, 0x809DC970,
0xE70747C4, 0x8275A0C0,
0xDAD7F3A2, 0x8582FAA4,
0xCF043AB2, 0x89BE50C2,
0xC3A94590, 0x8F1D343A,
0xB8E31318, 0x9592675C,
0xAECC336C, 0x9D0DFE54,
0xA57D8666, 0xA57D8666,
0x9D0DFE54, 0xAECC336C,
0x9592675C, 0xB8E31318,
0x8F1D343A, 0xC3A94590,
0x89BE50C2, 0xCF043AB2,
0x8582FAA4, 0xDAD7F3A2,
0x8275A0C0, 0xE70747C4,
0x809DC970, 0xF3742CA2,
0x80000000, 0x00000000,
0x809DC970, 0x0C8BD35E,
0x8275A0C0, 0x18F8B83C,
0x8582FAA4, 0x25280C5E,
0x89BE50C2, 0x30FBC54C,
0x8F1D343A, 0x3C56BA70,
0x9592675C, 0x471CECE6,
0x9D0DFE54, 0x5133CC94,
0xA57D8666, 0x5A82799A,
0xAECC336C, 0x62F201AC,
0xB8E31318, 0x6A6D98A4,
0xC3A94590, 0x70E2CBC6,
0xCF043AB2, 0x7641AF3C,
0xDAD7F3A2, 0x7A7D055A,
0xE70747C4, 0x7D8A5F40,
0xF3742CA2, 0x7F62368E,]
def main():
f_output = open(TEST_CSV_FILE, mode='wb')
# The CORDIC Q Format input
tmp_str = ("The CORDIC Q Format input\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
for q in test_q_angle_cordic:
if(q > INT32_MAX):
q = q - (1<<32)
f = q/(1<<31)
tmp_str = ("%08X , %f\n" % (q, f))
f_output.write(bytes(tmp_str, encoding="ansi"))
pass
tmp_str = ("\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
# The CMSIS DSP Q Format input
tmp_str = ("The CMSIS DSP Q Format input\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
for q in test_q_angle_cmsis_dsp:
if(q > INT32_MAX):
q = q - (1<<32)
f = q/(1<<31)
tmp_str = ("%08X , %f\n" % (q, f))
f_output.write(bytes(tmp_str, encoding="ansi"))
pass
pass
tmp_str = ("\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
# The Ref Sine Q Format input
tmp_str = ("The Ref Sine Q Format input\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
for q in test_q_ref_sin:
if(q > INT32_MAX):
q = q - (1<<32)
f = q/(1<<31)
tmp_str = ("%08X , %f\n" % (q, f))
f_output.write(bytes(tmp_str, encoding="ansi"))
pass
pass
tmp_str = ("\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
# The Ref Cos Q Format input
tmp_str = ("The Ref Cos Q Format input\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
for q in test_q_ref_cos:
if(q > INT32_MAX):
q = q - (1<<32)
f = q/(1<<31)
tmp_str = ("%08X , %f\n" % (q, f))
f_output.write(bytes(tmp_str, encoding="ansi"))
pass
pass
tmp_str = ("\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
# The Result of Cordic Calculation
tmp_str = ("The Result of Cordic Calculation\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
res_len = len(test_q_cordic_result)
for i in range(res_len//2):
q = test_q_cordic_result[2*i]
r = test_q_cordic_result[1 + (2*i)]
if(q > INT32_MAX):
q = q - (1<<32)
f = q/(1<<31)
if(r > INT32_MAX):
r = r - (1<<32)
g = r/(1<<31)
tmp_str = ("%08X , %f, %08X , %f\n" % (q, f, r, g))
f_output.write(bytes(tmp_str, encoding="ansi"))
pass
pass
tmp_str = ("\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
# The Result of CMSIS DSP Calculation
tmp_str = ("The Result of CMSIS DSP Calculation\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
res_len = len(test_q_cmsis_result)
for i in range(res_len//2):
q = test_q_cordic_result[2*i]
r = test_q_cordic_result[1 + (2*i)]
if(q > INT32_MAX):
q = q - (1<<32)
f = q/(1<<31)
if(r > INT32_MAX):
r = r - (1<<32)
g = r/(1<<31)
tmp_str = ("%08X , %f, %08X , %f\n" % (q, f, r, g))
f_output.write(bytes(tmp_str, encoding="ansi"))
pass
pass
tmp_str = ("\n")
f_output.write(bytes(tmp_str, encoding="ansi"))
#Generate Ref Sine output
print("The generated sine result")
for i in range(ARRAY_SIZE):
ang = (i * math.pi * 2)/ARRAY_SIZE
d_sin_res = math.sin(ang)
q_1_31_t = int(d_sin_res * (UINT32_MAX) / 2)
if(q_1_31_t < 0):
q_1_31_t = q_1_31_t + (1<<32)
#print("0x%08X, %f" % (q_1_31_t, d_sin_res))
print("0x%08X, " % q_1_31_t, end='')
if(0 == (i+1)%4):
print()
pass
print()
print("The generated cos result")
for i in range(ARRAY_SIZE):
ang = (i * math.pi * 2)/ARRAY_SIZE
d_cos_res = math.cos(ang)
q_1_31_t = int(d_cos_res * (UINT32_MAX) / 2)
if(q_1_31_t < 0):
q_1_31_t = q_1_31_t + (1<<32)
#print("0x%08X, %f" % (q_1_31_t, d_cos_res))
print("0x%08X, " % q_1_31_t, end='')
if(0 == (i+1)%4):
print()
pass
print()
if __name__ == '__main__':
main()
这些都有点枯燥, 但是用起来的话, 理解其实很容易.下面来做个简单的CORDIC运算的例子: 把[0,2PI]也就是一个圆的弧度空间分为64个点, 求每个点的正弦值. 首先把CORDIC外设打开: 图CORDIC配置配置就这么简单, 测试代码摘要如下, 整个工程代码在后文有下载连接.
|
带V3啊