STM32G474支持CORDIC,它coordinate rotation digital computer的缩写,意思是坐标旋转数字计算机,用于计算三角函数和双曲线函数,早期时候,广泛用于计算器当中。
在q1.31格式中,数字由一个符号位和31个小数位(二进制位)表示;数值范围是-1(0x80000000)到1 - 2^-31(0x7fffffff);精度是2^-31;
在q1.15格式中,数字由一个符号位和15个小数位(二进制位)表示;数值范围是-1(0x8000)到1 - 2^-15(0x7fff);
CORDIC提供了某些数学函数,特别是三角函数,采用硬件加速方式,取得三角函数的值。
在C语言中,若包含头文件“math.h”,我们就可以使用数学里的三角函数,显然这是采用软件方式取得三角函数的值。
软件能实现的,为什么要用硬件去实现呢,因为硬件速度快,可以很快得到我们想要的结果。
CORDIC的特点
可以计算正弦(sine)、余弦(cosine)、双曲正弦函数(sinh)、双曲余弦函数(cosh)、反正切(Atan)、反正切(Atan2)、反双曲正切(Atanh)、模数、平方根和自然对数。
1、测试程序
void CORDIC_Init(void)
{
Sin_CORDIC_INT();//用CORDIC算法实现正弦计算
// Cos_CORDIC_INT();//用CORDIC算法实现余弦计算
// Arctg_CORDIC_INT();//用CORDIC算法实现反正切计算
}
//函数功能: 用CORDIC算法实现正弦计算
void Sin_CORDIC_INT (void)
{
CORDIC_HandleTypeDef hcordic; //三角函数描述结构体
CORDIC_ConfigTypeDef sCordicConfig; //参数配置结构体
__HAL_RCC_CORDIC_CLK_ENABLE(); //开启时钟
hcordic.Instance = CORDIC; //选择三角函数计算单元
HAL_CORDIC_Init(&hcordic); //初始化
sCordicConfig.Function = CORDIC_FUNCTION_SINE; //选择计算正弦
sCordicConfig.Precision = CORDIC_PRECISION_6CYCLES; //选择计算精度等级
sCordicConfig.Scale = CORDIC_SCALE_0; //选择计算系数
sCordicConfig.NbWrite = CORDIC_NBWRITE_1; //选择计算结果个数
sCordicConfig.NbRead = CORDIC_NBREAD_1; //选择输出正弦
sCordicConfig.InSize = CORDIC_INSIZE_32BITS;
//选择输入数据格式Q1.31,在Q1.31格式的数字范围:-1 (0x80000000) to 1 至 2^(-31) (0x7FFFFFFF).
sCordicConfig.OutSize = CORDIC_OUTSIZE_32BITS; //选择数据输出格式Q1.31
HAL_CORDIC_Configure(&hcordic, &sCordicConfig); //初始化
}
//函数功能: 用CORDIC算法实现余弦计算
void Cos_CORDIC_INT (void)
{
CORDIC_HandleTypeDef hcordic; //三角函数描述结构体
CORDIC_ConfigTypeDef sCordicConfig; //参数配置结构体
__HAL_RCC_CORDIC_CLK_ENABLE(); //开启时钟
hcordic.Instance = CORDIC; //选择三角函数计算单元
HAL_CORDIC_Init(&hcordic); //初始化
sCordicConfig.Function = CORDIC_FUNCTION_COSINE; //选择计算余弦
sCordicConfig.Precision = CORDIC_PRECISION_6CYCLES; //选择计算精度等级
sCordicConfig.Scale = CORDIC_SCALE_0; //选择计算系数
sCordicConfig.NbWrite = CORDIC_NBWRITE_1; //选择计算结果个数
sCordicConfig.NbRead = CORDIC_NBREAD_1; //选择输出余弦
sCordicConfig.InSize = CORDIC_INSIZE_32BITS; //选择输入数据格式Q1.31
sCordicConfig.OutSize = CORDIC_OUTSIZE_32BITS; //选择数据输出格式Q1.31
HAL_CORDIC_Configure(&hcordic, &sCordicConfig); //初始化
}
//函数功能: 用CORDIC算法实现反正切计算
void Arctg_CORDIC_INT (void)
{
CORDIC_HandleTypeDef hcordic; //三角函数描述结构体
CORDIC_ConfigTypeDef sCordicConfig; //参数配置结构体
__HAL_RCC_CORDIC_CLK_ENABLE(); //开启时钟
hcordic.Instance = CORDIC; //选择三角函数计算单元
HAL_CORDIC_Init(&hcordic); //初始化
sCordicConfig.Function = CORDIC_FUNCTION_ARCTANGENT; //选择计算反正切
sCordicConfig.Precision = CORDIC_PRECISION_6CYCLES; //选择计算精度等级
sCordicConfig.Scale = CORDIC_SCALE_0; //选择计算系数
sCordicConfig.NbWrite = CORDIC_NBWRITE_1; //选择计算结果个数
sCordicConfig.NbRead = CORDIC_NBREAD_1; //选择输出
sCordicConfig.InSize = CORDIC_INSIZE_32BITS; //选择输入数据格式Q1.31
sCordicConfig.OutSize = CORDIC_OUTSIZE_32BITS; //选择数据输出格式Q1.31
HAL_CORDIC_Configure(&hcordic, &sCordicConfig); //初始化
}
//0<=angles<360,返回值在-1和1之间
//主频170MHz时,本函数执行时间330ns
float sin_f(float angles)
{
MODIFY_REG(CORDIC->CSR,CORDIC_CSR_FUNC|CORDIC_CSR_SCALE,CORDIC_FUNCTION_SINE|CORDIC_SCALE_0);
//选择计算类型:CORDIC_FUNCTION_SINE
WRITE_REG(CORDIC->WDATA, (int32_t)((180.0f-angles)*11930464.7f));
//小于180度为正数,大于180度为负数,乘以11930464.7就转换成“q1.31格式”的数据
//写入CORDIC_WDATA寄存器后,就可以读取“CORDIC_RDATA寄存器的数据”
//由于“模为0x80000000”,0x80000000/180=2147483648/180=11930464.7
return (int32_t)READ_REG(CORDIC->RDATA)/2147483648.0f;
//读取CORDIC_RDATA寄存器的数据是“q1.31格式”的数据,经过转换后,就是正弦值
//由于“模为0x80000000”,也就是2147483648,除以“模”后就得到正弦值,范围为[-1,1]
}
//0<=angles<360,返回值在-1和1之间
//主频170MHz时,本函数执行时间330ns
float cos_f(float angles)
{
MODIFY_REG(CORDIC->CSR,CORDIC_CSR_FUNC|CORDIC_CSR_SCALE,CORDIC_FUNCTION_COSINE|CORDIC_SCALE_0);
//选择计算类型:CORDIC_FUNCTION_COSINE
WRITE_REG(CORDIC->WDATA, (int32_t)((180.0f-angles)*11930464.7f));
//小于180度为正数,大于180度为负数,乘以11930464.7就转换成“q1.31格式”的数据
//写入CORDIC_WDATA寄存器后,就可以读取“CORDIC_RDATA寄存器的数据”
//由于“模为0x80000000”,0x80000000/180=2147483648/180=11930464.7
return -(int32_t)READ_REG(CORDIC->RDATA)/2147483648.0f;
//读取CORDIC_RDATA寄存器的数据是“q1.31格式”的数据,经过转换后,就是余弦值
//由于“模为0x80000000”,也就是2147483648,除以“模”后就得到正弦值,范围为[-1,1]
}
//-90<angles<90
//主频170MHz时,本函数执行时间660ns
float tg_f(float angles)
{
if(angles==90) return 0;
if(angles<0) angles=angles+180;
return( sin_f(angles)/cos_f(angles) );
}
//-128<=angles<128,返回值在-89.5°和89.5°之间
//主频170MHz时,本函数执行时间680ns
//arctg代表反正切函数
float arctan_f(float value)
{
static uint32_t CORDIC_SCALE_X_=0x00;
static float CORDIC_SCALE_X_f=0.0f;
static float value_1=0.0f;
static float value_2=0.0f;
value_1=value;
if(value<0)value=-value;
value_2=value;
if(value_2>128)return 0;
else if(value_2>64)
{
CORDIC_SCALE_X_=CORDIC_SCALE_7;
CORDIC_SCALE_X_f=128.0f;
}
else if(value_2>32)
{
CORDIC_SCALE_X_=CORDIC_SCALE_6;
CORDIC_SCALE_X_f=64.0f;
}
else if(value_2>16)
{
CORDIC_SCALE_X_=CORDIC_SCALE_5;
CORDIC_SCALE_X_f=32.0f;
}
else if(value_2>8)
{
CORDIC_SCALE_X_=CORDIC_SCALE_4;
CORDIC_SCALE_X_f=16.0f;
}
else if(value_2>4)
{
CORDIC_SCALE_X_=CORDIC_SCALE_3;
CORDIC_SCALE_X_f=8.0f;
}
else if(value_2>2)
{
CORDIC_SCALE_X_=CORDIC_SCALE_2;
CORDIC_SCALE_X_f=4.0f;
}
else if(value_2>1)
{
CORDIC_SCALE_X_=CORDIC_SCALE_1;
CORDIC_SCALE_X_f=2.0f;
}
else
{
CORDIC_SCALE_X_=CORDIC_SCALE_0;
CORDIC_SCALE_X_f=1.0f;
}
MODIFY_REG(CORDIC->CSR,CORDIC_CSR_FUNC|CORDIC_CSR_SCALE,CORDIC_FUNCTION_ARCTANGENT|CORDIC_SCALE_X_);
//选择计算类型:CORDIC_FUNCTION_ARCTANGENT
WRITE_REG(CORDIC->WDATA, (int32_t)(value_1*2147483648.0f/CORDIC_SCALE_X_f));
return (float)(int32_t)READ_REG(CORDIC->RDATA)*CORDIC_SCALE_X_f/11930464.7f;
}
void Test_sin_Cos(void)
{
float f;
f=sin_f(0);
printf("sin(0)=%0.3f ",f);
f=sin_f(30);
printf("sin(30)=%0.3f ",f);
f=sin_f(45);
printf("sin(45)=%0.3f ",f);
f=sin_f(60);
printf("sin(60)=%0.3f ",f);
f=sin_f(90);
printf("sin(90)=%0.3f\r\n",f);
f=cos_f(0);
printf("cos(0)=%0.3f ",f);
f=cos_f(30);
printf("cos(30)=%0.3f ",f);
f=cos_f(45);
printf("cos(45)=%0.3f ",f);
f=cos_f(60);
printf("cos(60)=%0.3f ",f);
f=cos_f(90);
printf("cos(90)=%0.3f\r\n",f);
f=tg_f(-30);
printf("tg(-30)=%0.3f ",f);
f=tg_f(-45);
printf("tg(-45)=%0.3f ",f);
f=tg_f(-60);
printf("tg(-60)=%0.3f ",f);
f=tg_f(0);
printf("tg(0)=%0.3f ",f);
f=tg_f(30);
printf("tg(30)=%0.3f ",f);
f=tg_f(45);
printf("tg(45)=%0.3f ",f);
f=tg_f(60);
printf("tg(30)=%0.3f\r\n",f);
f=arctan_f(0);
printf("arctg(0)=%0.1f ",f);
f=arctan_f( sqrt(3)/3 );
printf("arctg(sqrt(3)/3)=%0.1f ",f);
f=arctan_f(1);
printf("arctg(3)=%0.1f ",f);
f=arctan_f( sqrt(3) );
printf("arctg(sqrt(3))=%0.1f\r\n",f);
}
2、测试结果
3、问题
自然对数,开平方,双曲线 ,双曲正弦函数(sinh)、双曲余弦函数(cosh),怎么实现的?