XMC1300和XMC1400系列中集成了一个MATH协处理器,它与CPU核并行执行。MATH协处理由两个独立的单元组成,包含一个32位的除法器单元和一个24位的CORDIC单元,这两个单元可并行工作。除法器单元可实现32Bit有符号/无符号除法。CORDIC单元用于实现24Bit的三角、线性和双曲函数运算。PMSM的无感FOC控制要用到Clarke变换、Park变换、Park逆变换、位置估算等算法。 硬件的MATH协处理器对于实现无感FOC控制算法提供了良好的支持。
MATH协处理器支持内核时钟与接口时钟之比为2:1,以实现更快的执行速度。对于XMC13XX来说,CPU主时钟为32Mhz,MATH时钟即为64Mhz。对于XMC14XX,CPU主时钟为48Mhz,MATH时钟即为96Mhz。 除法器:在35个内核时钟内完成有符号/无符号除法运算,假设 q = D/d,r = D%d,那么其中,D是被除数(存入DVD寄存器),d是除数(存入DVS寄存器),q是商(存在QUOT寄存器),r是余数(存在RMD寄存器)。可通过DIVCON.USIGN位配置有无符号:DIVCON.USIGN =0,为有符号运算,DIVCON.USIGN =1,为无符号运算。当DIVCON.STMODE =1时,由软件设置DIVCON.ST位启动除法器。当DIVCON.STMODE =0时,写入DVS寄存器将直接启动除法运算。 CORDIC: CORDIC功能强大,可以进行三角、线性和双曲函数运算等。其数据寄存器为CORDX,CORDY,CORDZ,结果寄存器为CORRX,CORRY,CORRZ。 除法器单元内核和Cordic内核是独立的,因此应用程序可以同时使用这两个功能。例如,在PWM中断中,可以计算Sin和Cos函数,而在主循环中,也可以使用Div函数。但对于包含DIV和Cordic两种特性的函数,应用程序代码应防止高优先级事件同时调用此函数。 另外,除法器单元和CORDIC协处理器之间的结果可相互传递,DIV结果可以传递到CORDIC数据寄存器的输入端。同样,CORDIC结果也可以传递到DIV DVD和DVS寄存器的输入端。当DIV结果链接到CORDIC的CORDX时,如果CON.ST_MODE=0,则DIV计算的开始将设置DIV的BUSY标志,并设置CORDIC的BUSY标志。DIV操作完成后,结果被写入DIV的寄存器和CORDX,此时DIV的BUSY标志不会立即清除,在CORDIC计算完成后,DIV和CORDIC的BUSY标志才都被清除。
MATH协处理器的API分为阻塞式和非阻塞式。阻塞式API通过读取结果寄存器来查询结果。这会在总线上添加等待状态,直到结果准备就绪。在等待结果时,所有其他操作都被阻止,因此得名。非阻塞式API(函数名以NB (Non-Blocking)为后缀)启动所需的运算,然后将控制权返回给MCU。这允许其他操作继续进行。用户可以通过查询MATH协处理器的BUSY标志来检查计算是否已结束。当BUSY标志被清除时,用户可以读取计算结果。也可以采用中断的方式来进行。下面以ModusToolbox中提供的例程MATH_CORDIC工程为例:
可以看到main.c中包含头文件#include "xmc_math.h"。 CORDIC协处理器的X和Y数据输入可以直接以“Qm.n”格式进行。Q格式是一种二进制定点数字格式,其中指定了整数位数(由'm'表示)和小数位数(由'n'表示)。'Qm.n'格式通常用于没有浮点单元的MCU。 在这个代码示例中,使用了“Q0.23”和“Q1.22”格式: XMC_MATH_Q0_23_t表示1个有符号位,0个整数位,23个小数位 XMC_MATH_Q1_22_t表示1个有符号位,1个整数位、22个小数位 将Q格式转换为浮点数的函数在代码示例中实现,转换的理论是右移小数位以获得浮点值。对于线性运算,Z输入和输出数据也遵循相同的过程。然而,对于三角函数和双曲函数,结果数据和输入数据都被归一化。输入和输出都使用哪些寄存器请参考XMC手册中的表格CORDIC Coprocessor Operating Modes and Corresponding Result Data,比如cos:
根据手册所述,Z输入数据需要按比例放大((2^23)/pi)。例如,如果需要提供pi/3的Z输入,则输入到CORDIC协处理器的实际Z输入如下: ((pi/3)*((2^23)/pi)而三角函数和双曲函数的CORDIC单元的Z结果需要按((2^23)/pi)缩小。例如,如果CORDIC Z输出为(2^23)/pi,则实际的Z结果如下: ((2^23)/pi/((2^23)/pi))=1xmc_math.c中提供的cos函数有阻塞式和非阻塞式: 阻塞式: XMC_MATH_Q0_23_t XMC_MATH_CORDIC_Cos(XMC_MATH_Q0_23_t angle_in_radians){ int32_t result; MATH->STATC = 0U; /* Clear register */ MATH->CON = (uint32_t) XMC_MATH_CORDIC_OPERATING_MODE_CIRCULAR + \ (uint32_t) XMC_MATH_CORDIC_ROTVEC_MODE_ROTATION; MATH->CORDZ = ((uint32_t) angle_in_radians) << MATH_CORDZ_DATA_Pos; MATH->CORDY = 0U; /* Clear register */ MATH->CORDX = XMC_MATH_RECIPROC_CIRCULAR_GAIN_IN_Q023 << MATH_CORDX_DATA_Pos; result = ((int32_t)MATH->CORRX) >> MATH_CORRX_RESULT_Pos; return ((XMC_MATH_Q0_23_t) result);}非阻塞式: void XMC_MATH_CORDIC_CosNB(XMC_MATH_Q0_23_t angle_in_radians){ MATH->STATC = 0U; /* Clear register */ MATH->CON = (uint32_t) XMC_MATH_CORDIC_OPERATING_MODE_CIRCULAR + \ (uint32_t) XMC_MATH_CORDIC_ROTVEC_MODE_ROTATION; MATH->CORDZ = ((uint32_t) angle_in_radians) << MATH_CORDZ_DATA_Pos; MATH->CORDY = 0U; /* Clear register */ MATH->CORDX = XMC_MATH_RECIPROC_CIRCULAR_GAIN_IN_Q023 << MATH_CORDX_DATA_Pos;}样例中提供了阻塞式、非阻塞加中断方式读取运算结果、及直接寄存器非阻塞方式三种访问方法。 对于电机控制程序,为了加快程序的执行,可以给代码加上__RAM_FUN,使其在RAM中运行。 #if !defined(__RAM_FUNC)#if defined ( __CC_ARM )// http://www.keil.com/support/docs/3723.htm#define __RAM_FUNC __attribute__((section("RAMCODESECTION")))#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)#define __RAM_FUNC __attribute__((section("RAMCODESECTION")))#elif defined ( __ICCARM__ )// https://www.iar.com/support/tech-notes/linker/controlling-placement-of-the-section-where-__ramfunc-functions-reside-ewarm-5.x--6.x/#define __RAM_FUNC __ramfunc#elif defined ( __GNUC__ )#define __RAM_FUNC __attribute__((section(".ram_code"), long_call))#elif defined ( __TASKING__ )#define __RAM_FUNC __attribute__((section(".ram_code")))#endif#endif其中 __CC_ARM对应的平台是:Keil __ICCARM__对应的平台是:IAR EWARM __GNUC__对应的平台是:GNU Compiler Collection,ModusToolbox使用此项 __TASKING__对应的平台是:Altinum Designer;
|