本文對比均為作者實測,結果僅供參考,可附代碼供有意者評估~
STM32G431是STM32家族中較新的產品。CW32L012也是武漢芯源半導體最新推出的混合信號MCU,讓我們深入分析基于各自芯片CORDIC協處理器的三角運算性能對比。對比結果出乎意料。
一、硬件架構

二、運算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(timecount4000); //等待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(timecount4000); //???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); // } }
運算結果:

計算100W次SIN30度 與COS30度。其中運算結果數據表示為:CORDIC運算結果均為Q1.31格式表示 。
時間對比參考如下:

結果確實出乎意料,沒想到同樣的CORDIC協處理器運算,M4F內核的G4芯片表現竟不如M0+內核的CW32L012芯片!
為什么STM32G431會慢于CW32L012?我在瀏覽論壇時,也發現有人反饋G4的CORDIC表現差強人意。
作者猜想,STM32基于CUBE軟件生成的HALL庫文件中規則性判斷語句較多,可能會引起一定時間的延遲。
另外應該還有其它原因?!
下表是兩款芯片在不同條件下,計算100W次SIN30度與COS30度的時間快慢表現。

最后溫馨提示:STM32G431帶有DSP功能,DSP運算比CORDIC要快。 對比測試作為性能評估參考。大家根據自己項目定位和預算,選擇合適性能的芯片就可以了。
審核編輯 黃宇
-
CORDIC
+關注
關注
0文章
41瀏覽量
20540
發布評論請先 登錄
FOC控制中如何利用芯片內部的運放設計電流采樣電路?
CW32L012小型機器人控制評估板活動 四足機器人+智能小車 開箱評測
**CW32L012****開發評估板的第一個程序**
CW32L012小機器人的電機控制
使用芯源CW32的CW32L012開發評估板做了spi屏幕驅動
堅持繼續布局32位MCU,進一步完善產品陣容,96Mhz主頻CW32L012新品發布!
CW32L012與STM32G431的CORDIC三角函數運算性能對比
評論