CW32L012与STM32F103的三角运算性能对比 电子说
CW32L012和STM32F103在定位和性能上差异显著,在三角函数的运算性能上的对比亦非常直观。
一、 硬件架构对比(性能基础)
| 芯片型号 | CW32L012C8 | STM32F103C8 |
|---|---|---|
| 内核 | ARM Cortex-M0+ | ARM Cortex-M3 |
| 主频 | 最高 96 MHz | 最高 72 MHz |
| 硬件CORDIC | 支持 | 无 |
| DSP | 无 | 无 |
| 立创样片价格 | 3.69元 | 7.55元 |
两者都没有硬件浮点运算单元。 但在运算三角函数时,CW32L012支持CORDIC算法。
二、 三角运算性能具体分析
1:标准库浮点运算(如 math.h 的 sinf, cosf)
这是最常用但也是最慢的方式。
STM32F103C8:Cortex-M3内核的整体性能,使其在运行相同的软件浮点库时,性能优于CW32L012的Cortex-M0+。
CW32L012C8:Cortex-M0+内核设计更简单,但用软件浮点运算效率较低,耗时会更长。
以下是使用STM32F103C8T6和CW32L012C8T6两种芯片。使用math.h运算SIN和COS的代码实现。
STM32F103使用math.h运算SIN30度与COS30度 :
float angle;
void performance_test(unsigned long iterations)
{
unsigned long i=0;
float y1,y2;
for(i=1;i<=iterations;i++)
{
y1=sin(angle);
y2=cos(angle);
}
}
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void TIM1_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_InternalClockConfig(TIM1);
TIM_TimeBaseInitTypeDef TIM1_Initstructure;
TIM1_Initstructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM1_Initstructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM1_Initstructure.TIM_Period=1000-1; //定时时长=72000000/(Prescaler-1)/(Period-1)
TIM1_Initstructure.TIM_Prescaler=72-1;
TIM1_Initstructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1,&TIM1_Initstructure);
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);
TIM_ClearFlag(TIM1,TIM_IT_Update);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_Initstructure;
NVIC_Initstructure.NVIC_IRQChannel=TIM1_UP_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_Initstructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_Initstructure);
TIM_Cmd(TIM1,ENABLE);
}
unsigned int timecount=0;
unsigned int lastcmputetime=0;
int main(void)
{
char temp_buff1[40];
LED_Init();
TIM1_Init();
OLED_Init(); //清屏
OLED_Printf(0,0,OLED_6X8," SIN/COS COMPUTE Test ");
OLED_Printf(0,16,OLED_6X8," For 1000000 Times ");
OLED_Update();
angle=0.523; //0.785(45度弧度制)=45度/180度*3.14 0.523(30度弧度制)=30/180*3.14
while (1)
{
sprintf(temp_buff1, " STM32F103 start...... ");
OLED_Printf(0, 32, OLED_6X8, temp_buff1);
OLED_Printf(0, 48, OLED_8X16, " ");
OLED_Update();
timecount=0;
performance_test(1000000);
lastcmputetime=timecount;
sprintf(temp_buff1, " STM32F103 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();
while(1); //由于结果太慢,不进行二次运算,停在这里方便查看时间. 如果需要二次运算,则屏蔽该条语句
timecount=0;
while(timecount< 4000); //等待2S
}
}
void TIM1_UP_IRQHandler(void)
{ static unsigned int flag=0;
if(TIM_GetITStatus(TIM1,TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM1,TIM_IT_Update);
timecount++;
// if(timecount >=500) //以下用于检查时间配置是否准确
// {timecount=0;
// flag=1-flag;
// if(flag==1)
// GPIO_SetBits(GPIOC,GPIO_Pin_13);
// else
// GPIO_ResetBits(GPIOC,GPIO_Pin_13);
// }
}
}

使用MATH.H执行结果:运算100W次SIN30度与COS30度时间显示内容如下:

CW32L012使用math.h运算SIN30度与COS30度:
核心代码:
void performance_test(unsigned long iterations)
{
unsigned long i=0;
float y1,y2;
CW_FLASH- >CR2 = 0x5a5a001B;
for(i=1;i<=iterations;i++)
{
y1=sin(anglef);
y2=cos(anglef);
}
CW_FLASH- >CR2 = 0x5a5a0003;
}

使用MATH.H执行结果:运算100W次SIN30度与COS30度时间显示内容如下:

2:使用硬件CORDIC
CORDIC是一种用移位和加法实现三角、双曲等函数的算法。CW32L012的CORDIC提供某些数学函数的硬件加速,特别是三角函数,通常用于电机控制、计量、信号处理和许多其他应用。与软件实现相比,它加快了这些功能的计算速度,允许较低的工作频率,或释放处理器周期以执行其他任务。
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 */
}

运算结果:

计算100W次SIN30度 与COS30度。其中运算结果数据表示为:CORDIC运算结果为Q1.31格式表示;math.h:运算结果为浮点数表示。
时间对比参考如下:

审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !