需求:IO产生最快的翻转脉冲。
结论:最快速度5MHz.
第一次尝试:
IRC使能16M,不分频。
IO设置为推挽高速输出。
While(1)死循环翻转。
代码如下:
void main(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //16M
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_SLOW);
while(1)
{
GPIO_WriteReverse(GPIOD, GPIO_PIN_3);
}
}
实际波形如下:
结果是只有463KHz,达不到要求。
反思是有一层函数调用的原因,没有及时翻转。
第二次尝试:
把函数去掉直接操作。
代码如下:
void main(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //16M
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_SLOW);
while(1)
{
GPIOD->ODR ^= (uint8_t)GPIO_PIN_3;
}
}
实际波形如下:
结果已经有好转,翻转有1.311MHz。离目标还是有点远。
反思通过结构体访问寄存器,使用的是间接寻址,消耗了时间。
第三次尝试:
直接对硬件地址操作。
代码如下:
void main(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //16M
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_SLOW);
while(1)
{
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
}
}
实际波形如下:
结果已经又有了进步,翻转速度是3.143Mhz.还是没有达到理想效果。
反思为什么是高电平比低电平多,是置高然后循环跳转回去指令耗时了。跳转指令有没有办法精简。
第四次尝试:
改循环语句。
代码如下:
void main(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //16M
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_SLOW);
/*
while(1)
{
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
}
*/
/*
for(;;)
{
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
}
*/
_LoopWrite:
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
goto _LoopWrite;
}
实际汇编翻译效果:
这三种循环汇编跳转都是JRA,所以没有达到提速的效果。尝试失败。
反思是跳转耽误了时间,那尽可能的翻转,少跳转。
第五次尝试:
用空间换速度,多重复几次翻转,然后才循环。
代码如下:
void main(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //16M
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_SLOW);
while(1)
{
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
*((uint8_t *)GPIOD_BaseAddress) = 0;
*((uint8_t *)GPIOD_BaseAddress) = 0x08;
}
}
实际波形图如下:
结果已经又有了进步,翻转速度是5.266Mhz.但是可以看到中间因为循环跳转指令带来的延时非常明显。
反思那足够多的重复指令,然后才接一次循环,就可以无限接近于没有跳转的效果。
尝试的结果是不会。当重复到一定次数,ROM存储空间存在跨页,跳转的时候会编译变长跳转,长跳转的指令周期比当前跳转机器周期长。
如果只是使用IO翻转,最大的速度只能到这么多了。
反思如果是有程序参与导致翻转速度受指令限制,那么硬件自己反应,应该比这个快。
第六次尝试:
使用PWM翻转。
代码如下:
void main(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //16M
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_SLOW);
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_1, 0x0001);
TIM2_OC2Init(TIM2_OCMODE_TOGGLE, TIM2_OUTPUTSTATE_ENABLE,
0x0000, TIM2_OCPOLARITY_HIGH);
TIM2_Cmd(ENABLE);
while(1)
{
}
}
实际波形图如下:
结果是3.943MHz,没有比IO直接翻转来得快。
反思是比较器比较的时候消耗了时间。
结论,IO最大的翻转速度是访问硬件地址直接操作IO。
上一篇:使用STM8S自带BootLoader_2
下一篇:STM8 入门学习与实验(一)GPIO与UART
推荐阅读最新更新时间:2024-11-17 17:19
设计资源 培训 开发板 精华推荐
- Others
- AD8532ARUZ-REEL 单电源直接接入调制解调器的典型应用
- NCP702MX28TCGEVB:2.8 V LDO 线性稳压器评估板
- LT8390IUFD 98% 效率 48W (12V/4A) 微型降压-升压稳压器的典型应用电路
- LT1510 的典型应用 - 恒压/恒流电池充电器
- L78L18AC输出升压电路正电压稳压器的典型应用
- LTM8003IY 0.97Vout 3.4 至 40Vin 降压转换器的典型应用电路,具有扩频功能
- 使用 STMicroelectronics 的 L6984 的参考设计
- 用于射频和模拟电路的 NCP160 250 mA、超低噪声和高 PSRR LDO 稳压器的典型应用
- 使用具有调节功能的 LT1054ISW 正倍增器的典型应用