当前位置:首页 > 财经频道 > 正文内容

CW32L012与STM32G431的CORDIC三角函数运算性能对比

聚亿千财2025-12-30财经频道3079

本文对比均为作者实测,结果仅供参考,可附代码供有意者评估~

STM32G431是STM32家族中较新的产品。CW32L012也是武汉芯源半导体最新推出的混合信号MCU,让我们深入分析基于各自芯片CORDIC协处理器的三角运算性能对比。对比结果出乎意料。

一、硬件架构

wKgZO2lSMoWACLs6AACFW1xwJ3k646.png

二、运算100W次SIN30度与COS30度的代码实现

1.CW32L012

CW32L012的CORDIC提供某些数学函数的硬件加速,特别是三角函数9,通常用于电机控制、计量、信号处理和许多其他应用。与软件实现相比,它加快了这些功能的计算速度,允许较低的工作频率,或释放处理器周期以执行其他任务。

CW32L012的CORDIC支持余弦 cos、正弦 sin、相位角 atan2、模 hypot、反正切 atan、双曲余弦 cosh、双曲正弦 sinh、双曲反正切 atanh 函数运算。

CW32L012使用CORDIC运算100W次SIN30度与COS30度的代码实现如下:

 
int32_t angle; 
 
void RCC_Configuration(void)
{
   SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV1);
    SYSCTRL_HCLKPRS_Config(SYSCTRL_HCLK_DIV1);
    SYSCTRL_PCLKPRS_Config(SYSCTRL_PCLK_DIV1);
    SYSCTRL_SystemCoreClockUpdate(96000000);
}
void performance_test1(unsigned long iterations)
{
 unsigned long i=0;
  int32_t  y1,y2;
  float  y11,y22;  
 for(i=1;i<=iterations;i++)
 {       
  while (CORDIC_GetStatus().busy);  
    CW_CORDIC- >Z =angle; // 写入Z寄存器启动运算    
    // 等待运算完成
    while (!CORDIC_GetStatus().eoc); //运算完成标志硬件置1,读取运算结果硬件清0
    // 读取结果  
//y1=CW_CORDIC->Y;//sin(PI/6);  // 正弦结果在Y寄存器 Q1.31格式 根据需要使用
//y2=CW_CORDIC->X;//cos(PI/6); // 余弦结果在X寄存器 Q1.31格式 根据需要使用
  //y11=q1_31_to_float(y1);   //正弦结果转浮点数 根据需要使用
  //y22=q1_31_to_float(y2);   //余弦结果转浮点数 根据需要使用
 }
}
void BTIM1_Configuration(void)     //1ms进一次中断
{
 BTIM_TimeBaseInitTypeDef BTIM_TimeBaseInitStruct = {0}; 
 __SYSCTRL_BTIM123_CLK_ENABLE();
  __disable_irq();
  NVIC_EnableIRQ(BTIM1_IRQn);
  __enable_irq(); 
 BTIM_TimeBaseInitStruct.BTIM_Mode = BTIM_MODE_TIMER; 
  BTIM_TimeBaseInitStruct.BTIM_Period = 1000 - 1;
  BTIM_TimeBaseInitStruct.BTIM_Prescaler = 96 - 1;    // 8
  BTIM_TimeBaseInit(CW_BTIM1, &BTIM_TimeBaseInitStruct); 
  BTIM_ITConfig(CW_BTIM1, BTIM_IT_UPDATE, ENABLE);
  BTIM_Cmd(CW_BTIM1, ENABLE);
}
unsigned int timecount=0;
unsigned int lastcmputetime=0;
int main(void)
{ 
    GPIO_InitTypeDef GPIO_InitStruct;
    char temp_buff1[4]; 
    RCC_Configuration();//时钏配置 
  cordic_init_t init = {
        .func = CORDIC_FUNC_COS,  // 选择余弦函数
        .scale = 0,              // 不使用扩展范围
        .format = CORDIC_FORMAT_Q1_31, // 使用q1.31格式
        .iter = CORDIC_ITER_20,  // 迭代次数
        .comp = 1,               // 硬件补偿伸缩因子
        .ie = 0,                 // 禁用中断
        .dmaeoc = 0,             // 禁用DMA
        .dmaidle = 0             // 禁用DMA空闲
    };  
  CORDIC_Init(&init);  //sin cos运算初始化    
    EAU_Init();// 初始化EAU    
   EAU_SetMode(EAU_MODE_UNSIGNED_DIV);// 设置为无符号除法模式       
  __SYSCTRL_GPIOC_CLK_ENABLE();    //GPIOC LED
    GPIO_InitStruct.Pins = GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init( CW_GPIOC, &GPIO_InitStruct);
    GPIO_WritePin(CW_GPIOC,GPIO_PIN_13,GPIO_Pin_RESET);
  BTIM1_Configuration(); //1MS    
     OLED_Init();               //清屏
      OLED_Printf(0,0,OLED_6X8," SIN/COS COMPUTE Test ");
   OLED_Printf(0,16,OLED_6X8,"  For 1000000 Times ");   
   OLED_Update();     
   angle = float_to_q1_31(0.167);//float_to_q1_15   // 0.25=1/4,即:运算45度=PI/4,换算为Q1.31格式,   //0.167=1/6 PI/6=30度
  while (1)
    {   
   sprintf(temp_buff1, " CW32L012 start......      ");
      OLED_Printf(0, 32, OLED_6X8, temp_buff1);
      OLED_Printf(0, 48, OLED_8X16, "                 ");
   OLED_Update();   
   timecount=0;
   performance_test1(1000000);
   lastcmputetime=timecount;      
   sprintf(temp_buff1, " CW32L012 used time:    ");
      OLED_Printf(0, 32, OLED_6X8, temp_buff1);
   sprintf(temp_buff1, "     %d mS    ", lastcmputetime);
      OLED_Printf(0, 48, OLED_8X16, temp_buff1);OLED_Update();   
   timecount=0;
   while(timecount< 4000); //等待2S
    }   
}
void BTIM1_IRQHandler(void)
{
  /* USER CODE BEGIN */
  if (BTIM_GetITStatus(CW_BTIM1, BTIM_IT_UPDATE))
  {
     BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_UPDATE);     
     timecount++;
 }
  /* USER CODE END */
}

运算结果:

2.STM32G431



/* Private variables ---------------------------------------------------------*/
CORDIC_HandleTypeDef hcordic;
DMA_HandleTypeDef hdma_cordic_read;
DMA_HandleTypeDef hdma_cordic_write;
 
TIM_HandleTypeDef htim2;
 
/* USER CODE BEGIN PV */
 
/* Array of calculated sines in Q1.31 format */
static int32_t aCalculatedSin[2];
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM2_Init(void);
static void MX_CORDIC_Init(void);
/* USER CODE BEGIN PFP */
CORDIC_ConfigTypeDef sCordicConfig;
 
int32_t angle; 
float anglef;
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
unsigned int timecount=0;
unsigned int lastcmputetime=0;
void performance_test3(unsigned long iterations) //使用cordic功能运算
{
 unsigned long i=0;
 int32_t y1,y2;
 float result;
  float  y11,y22;
 for(i=1;i<=iterations;i++)
 {
  while (HAL_CORDIC_GetState(&hcordic) != HAL_CORDIC_STATE_READY)
  {
  } 
  if (HAL_CORDIC_Calculate_DMA(&hcordic, &angle, aCalculatedSin,1, CORDIC_DMA_DIR_IN_OUT) != HAL_OK)
  {
   Error_Handler();
  }    
 
//  y1=aCalculatedSin[0]; //SIN运算结果Q1.31格式
//  y2=aCalculatedSin[1]; //COS运算结果Q1.31格式
//   y11=(float)y1 / 2147483648.0; // 2^31  换算成符点数 正弦结果转浮点数 根据需要使用
//   y22=(float)y2 / 2147483648.0; // 2^31  换算成符点数 余弦结果转浮点数 根据需要使用
 }
} 
 
/* USER CODE END 0 */
 
/**
@brief  The application entry point.
@retval int
*/
int main(void)
{
  /* USER CODE BEGIN 1 */
  char temp_buff1[50];
  /* USER CODE END 1 */
  /* MCU Configuration--------------------------------------------------------*/
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* USER CODE BEGIN Init */
  /* USER CODE END Init */
  /* Configure the system clock */
  SystemClock_Config();
  /* USER CODE BEGIN SysInit */
  /* USER CODE END SysInit */
  /* Initialize all configured peripherals /
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
  MX_CORDIC_Init();
  / 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_2;          / 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)
  {
    /* Configuration Error */
    Error_Handler();
  }  
  HAL_TIM_Base_Start_IT(&htim2);
  OLED_Init();
  OLED_Printf(0,0,OLED_6X8," SIN/COS COMPUTE Test ");
  OLED_Printf(0,16,OLED_6X8,"  For 1000000 Times ");
 OLED_Update();
 angle=(int32_t)round(0.167 * 2147483648.0); // 2^31 // 0.25=1/4,即:运算45度=PI/4,换算为Q1.31格式,   //0.167=1/6 PI/6=30度
 anglef=0.523; //0.785(45度弧度制)=45度/180度*3.14  0.523(30度弧度制)=30/180*3.14
  /* USER CODE END 2 */
  /* Infinite loop /
  / USER CODE BEGIN WHILE /
  while (1)
  {
    / USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    sprintf(temp_buff1, " STM32G431 start......      ");
      OLED_Printf(0, 32, OLED_6X8, temp_buff1);
      OLED_Printf(0, 48, OLED_8X16, "                 ");
   OLED_Update();
   timecount=0;
   performance_test3(1000000);
   lastcmputetime=timecount;  
   sprintf(temp_buff1, " STM32G431 used time:    ");
      OLED_Printf(0, 32, OLED_6X8, temp_buff1);
   sprintf(temp_buff1, "     %d mS    ", lastcmputetime);
      OLED_Printf(0, 48, OLED_8X16, temp_buff1);
    OLED_Update();  
     timecount=0;
   while(timecount< 4000); //�ȴ�2S
  }
  /* USER CODE END 3 */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 static unsigned int flag=0;
  /* Prevent unused argument(s) compilation warning */
  if(htim- >Instance==TIM2)
 {
  timecount++;
//  if(timecount>=500) 
//  {timecount=0;
//   flag=1-flag;
//   HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
//  }
 }

运算结果:

wKgZO2lSM46AVrH4AATz6k7S6Sg451.png

计算100W次SIN30度 与COS30度。其中运算结果数据表示为:CORDIC运算结果均为Q1.31格式表示 。

时间对比参考如下:

结果确实出乎意料,没想到同样的CORDIC协处理器运算,M4F内核的G4芯片表现竟不如M0+内核的CW32L012芯片!

为什么STM32G431会慢于CW32L012?我在浏览论坛时,也发现有人反馈G4的CORDIC表现差强人意。

作者猜想,STM32基于CUBE软件生成的HALL库文件中规则性判断语句较多,可能会引起一定时间的延迟。

另外应该还有其它原因?!

下表是两款芯片在不同条件下,计算100W次SIN30度与COS30度的时间快慢表现。

wKgZPGlSM8OAchK1AACFa2c1EiE104.png

最后温馨提示:STM32G431带有DSP功能,DSP运算比CORDIC要快。 对比测试作为性能评估参考。大家根据自己项目定位和预算,选择合适性能的芯片就可以了。

审核编辑 黄宇