STM32G474之CORDIC

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),怎么实现的?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值