《APM32芯得》系列内容为用户使用APM32系列产品的经验总结,均转载自21ic论坛极海半导体专区,全文未作任何修改,未经原文作者授权禁止转载。
1 背景
近期有小伙伴讨论到APM32F103ZE的GPIO翻转速度极限值是多少?他用C语言的GPIO翻转速度远远达不到。本文章对APM32F103ZE的GPIO翻转速度的最大值的测试过程进行梳理分享。
2 APM32F103ZE基本规格
首先我们先去确认一下APM32F103ZE基本规格:
1. 主频:96MHz
2. GPIO处于APB2时钟上,最大频率支持96MHz。
注:我的测试平台是APM32F103ZET6 MINI板,测试引脚是PE5/PE6。
3 GPIO翻转频率测试
常见的GPIO翻转的测试非常简单,使用C语言编写,深究底层就是控制其输出寄存器,不断重复输出0/1此时便是翻转。但我们这里是测试极限速度,我们需要注意主频(包括GPIO所在的APB2时钟)要求是最高,GPIO模式什么的也要求设置为最高值。
梳理我们的需求,输出我们的测试步骤:
1. 设置主频为96MHz。
2. AHB与APB2不分频。
3. GPIO初始化为推挽输出模式、速度设置为50MHz。
4. 设置GPIO的BSC与BC寄存器(或者是ODATA寄存器),使其交替输出0/1。
3.1 C语言函数版本
这个版本的测试代码与我们LED闪烁的频率并无不同,仅是把延时取消掉即可。
代码直接调用:APM_MINI_LEDToggle函数即可。
测试情况如下:
发现速度仅1MHz这样而已。
难道速度仅此而已了么?由于C语言的函数调用是有一定的消耗(函数的调用涉及出栈入栈等消耗)。那我们进阶一下呢?直接操作寄存器呢?
3.2 C语言寄存器版本
我们把C语言库函数最深层的内容的寄存器表达直接写在main函数里面的while循环里 面,以减少由于函数的调用的损耗。
参考代码如下:
APM_MINI_LEDInit(LED2);
APM_MINI_LEDInit(LED3);
while (1)
{
{// 这两者是一致的
// GPIOE->ODATA = 0x00000060;
// GPIOE->ODATA = 0x00000000;
GPIOE->BSC = 0x00000060;
GPIOE->BC = 0x00000060;
}
}
我们查看示波器:
我们发现,频率确实有所提升但是这个波形十分奇怪:理论上的高低电平的占比比是不一致的。为什么呢?
我们查看一下反汇编代码:
如图所示,我们发现使得GPIO翻转的汇编指令分别为第3/5条的STR指令,这两个指令直接的间隔指令数量并不一致,所以导致了最终输出的波形占空比有问题:
1. 指令3至指令5:中间间隔指令4。
2. 指令5至指令3:中间间隔指令6、1、2。
3.3 汇编版本1
为了测试极限值,我们把翻转GPIO的功能写成汇编代码,汇编代码的加入大家可以查阅网上的资料。我这里直接新建一个.s文件,在该文件中编写测试的代码。
在测试函数1中,我们把寄存器的赋值等内容放在循环外面,循环中仅进行GPIO的翻转,不做其他事情。
参考代码如下:
gpio_toggle_speed_1 PROC
LDR R0, =0x40011800 ; Load the address of GPIOE ODR into R0
LDR R1, =0x60 ; Load the toggle value into R1
toggle_1
STR R1, [R0, #0x10] ; Store R1 into GPIOE BSRR register (Set bits)
STR R1, [R0, #0x14] ; Store R1 into GPIOE BRR register (Reset bits)
B toggle_1 ; Branch unconditionally to 'toggle' label
ENDP
测试波形如下:
频率进一步提高,但是占空比依旧有所问题,那消耗在哪里呢?是的,正如前文所说,跳转指令“B”导致的。
3.4 汇编版本2
由此,我们把翻转的代码增多,这样子相比之下跳转指令的影响就减少了。
频率来到了24MHz左右!那这个会不会是最高频率了呢?我们把主频提升至120MHz(超频),发现频率已经无法上升,或者设置其程序运行至RAM也无法提升。
4 测试总结
按照本文的测试方法,APM32F103ZE的GPIO翻转理论最大速度基本为24MHz这样。你有什么好的测试方案么?欢迎在评论区留言。
注:文章作者在原帖中提供了工程文件,有需要请至原文21ic论坛下载
原文地址:https://bbs.21ic.com/icview-3359596-1-1.html
或点击下方 阅读原文 跳转
↑↑↑ 点击上方卡片关注极海 ↑↑↑