STM32G474单片机开发入门(十九)Cordic 三角函数协处理器详解及实战
本文介绍了STM32G474RET6的Cordic 三角函数协处理器,很方便计算Sin,Cos等三角函数,减少CPU干预,适合电机控制等场景。
文章目录
一.概要
CORDIC(Coordinate Rotation Digital Computer)算法是一种基于迭代的硬件友好型数学计算方法,最初由Jack Volder于1959年为解决航空导航系统中的实时三角函数计算问题而提出。其核心思想是通过一系列固定角度的旋转操作,将复杂运算(如三角函数、双曲函数、乘除等)分解为仅需加减和移位的简单操作,从而显著降低硬件实现复杂度。
STM32G4系列芯片集成CORDIC协处理器,通过定点带符号整数数据格式实现三角函数硬件加速,显著降低处理器负载,该设计特别适用于电机控制、测量等实时性要求高的场景,支持正弦、余弦、双曲函数等10种数学运算。
二.STM32G474RET6单片机CORDIC外设特点
STM32G4 CORDIC支持以下函数:
CORDIC以定点有符号整型数进行运算,内部采用Q1.23格式,输入/输出支持Q1.31(32位)或Q1.15(16位)格式,最高精度需使用Q1.31,精度范围如下图所示。
角度采用(角度/π )来表述,这样就可以更加高效的通过定点数格式来表示角度,-1代表-π , +1代
表+π。
输入角度需严格限制在[-π, π]弧度内,超出范围需预处理(如取模),否则结果误差显著增大。
如下图所示,设置Cordic时可以选定迭代次数(Iterations),为4的倍数。一个时钟周期可以执行4次迭代,如果需要最高的精度,Number of cycles需要配置成6。考虑最快的速度,在达到需要精度的情况下,选用最少的迭代次数。
三.STM32G474单片机CORDIC基本操作
基本函数操作如下所示:
uint32_t angle = 0x40000000; // π/2弧度(Q1.31)
uint32_t result;
HAL_CORDIC_Calculate(&hcordic, &angle, &result); // 单次计算
float cos_value = (float)result / (1 << 30); // Q1.31结果需转换为浮点值
0x40000000表示π/2弧度(即90°),这是由Q1.31定点数格式的编码规则决定的,Q1.31是一种定点数格式,其中符号位:最高位(第31位)表示正负(0为正,1为负),第30位到第0位表示数值,小数部分占31位,无整数位。π的十进制值约为3.141592653589793,π/2约为1.5707963267948966,1.5707963267948966 × 2^30 ≈ 0x40000000(十六进制),0x40000000是π/2的合法表示,可直接用于计算余弦或正弦。
四.CubeMX配置一个Cordic例程
1.硬件准备
STLINK接STM32G474RET6开发板,STLINK接电脑USB口。
2.创建CubeMX工程
如下图所示,打开STM32CubeMX软件,新建工程。
如下图所示,Part Number处输入STM32G474RE,再双击就创建新的工程。
如下图所示,配置下载口引脚,PA13为SWD的SWDIO脚,PA14为SWD的SWCLK脚。
PC8配置成输出。
配置Cordic,使用DMA方式进行读写。
如下图所示,配置系统主频170Mhz,使用内部16MHZ晶振。
如下图所示,配置工程文件名,保存路径,KEIL5工程输出方式。
如下图所示,生成工程。
如下图所示,增加角度的表格,与计算结果的表格。
如下图所示,调用Cordic计算Sin值,与表格里的Sin值结果比较,如果一致,LED灯闪烁。
主要代码如下
//需要计算SIN的角度值
static int32_t aAngles[ARRAY_SIZE] =
{
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
};
/* Array of reference sines in Q1.31 format */
//参考的SIN值
static int32_t aRefSin[ARRAY_SIZE] =
{
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
};
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();//SysTick配置成1ms中断
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();//16M内部晶振,170MHZ系统主频
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();//PC8配置成输出
MX_DMA_Init();//DMA1通道1通道2中断使能
MX_CORDIC_Init();//CORDIC初始化
/* USER CODE BEGIN 2 */
sCordicConfig.Function = CORDIC_FUNCTION_SINE; /* sine function */
sCordicConfig.Precision = CORDIC_PRECISION_6CYCLES; /* max precision for q1.31 sine */
sCordicConfig.Scale = CORDIC_SCALE_0; /* no scale */
sCordicConfig.NbWrite = CORDIC_NBWRITE_1; /* One input data: angle. Second input data (modulus) is 1 after cordic reset */
sCordicConfig.NbRead = CORDIC_NBREAD_1; /* One output data: sine */
sCordicConfig.InSize = CORDIC_INSIZE_32BITS; /* q1.31 format for input data */
sCordicConfig.OutSize = CORDIC_OUTSIZE_32BITS; /* q1.31 format for output data */
if (HAL_CORDIC_Configure(&hcordic, &sCordicConfig) != HAL_OK)//CODIC SIN函数配置
{
/* Configuration Error */
Error_Handler();
}
/*## Start calculation of sines in DMA mode #############################*/
if (HAL_CORDIC_Calculate_DMA(&hcordic, aAngles, aCalculatedSin,
ARRAY_SIZE, CORDIC_DMA_DIR_IN_OUT) != HAL_OK)//cordic计算SIN值
{
/* Processing Error */
Error_Handler();
}
while (HAL_CORDIC_GetState(&hcordic) != HAL_CORDIC_STATE_READY)//查询是否计算完
{
}
for (uint32_t i = 0; i < ARRAY_SIZE; i++)
{
if (Check_Residual_Error(aCalculatedSin[i], aRefSin[i], DELTA) == FAIL)//比较cordic计算的SIN值与查表法的SIN值,如果两者差异大,ErrCounter++
{
ErrCounter++;
}
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(ErrCounter==0)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_8);//翻转输出,LED闪烁
HAL_Delay(200);
}
}
/* USER CODE END 3 */
}
3.实验效果
Cordic计算的SIN值与查表法的SIN值,两个SIN值接近,可以看到LED能间隔闪烁。
五.小结
Cordic配合DMA可减少CPU干预,适合电机控制等实时场景,通过Cordic快速计算正弦/余弦值,生成PWM波形驱动无刷直流电机(BLDC)或永磁同步电机(PMSM),也可以用在加速计/陀螺仪数据融合时,计算姿态角(如四元数转欧拉角)。
更多推荐



所有评论(0)