本帖为继续为大家分享实战技能。
一、内联函数Inline function:
内联函数就是带inline关键字修饰的函数,作用是将函数直接嵌入到调用此函数的代码中,从而降低调用此函数所占用的时间。
典型的像CMSIS软件包,ST的LL库都开始采用内联的定义方式,这类函数特点是简短,适合需要频繁调用的场景。因为这样才能发挥内联的优势:
LL库这里用的关键字是__STATIC_INLINE,这个是ARM的CMSIS软件包专门做的定义方式,对MDK,IAR和GCC都做了适配,通用。
二、内联汇编Inline assembler:
内联汇编可以将汇编程序指令直接插入到 C 或 C 函数中。通常,如果需要访问在 C 中不可访问的硬件资源或者编写时间关键的代码序列,使用内联汇编非常方便。
内联汇编程序类似 C 函数,也可以有形参和返回值。
这个的典型代表是CMSIS软件包,由于要访问一些内核寄存器,所以C里面嵌入汇编再合适不过了。 cmsis_armcc.h :对应MDK AC5头文件 cmsis_gcc.h : 对应各种基于GCC的编译器头文件 cmsis_clang.h : 对应MDK AC6头文件 cmsis_iccarm.h : 对应IAR头文件 比如我们常用的函数__set_MSP设置主堆栈指针,实现如下:
又比如32bit变量赋值的原子操作,由于要用到互斥指令ldrex和strex,通过内联汇编,就可以方便的在各种编译器里实现:
三、内部函数Instruction Intrinsics
使用内联汇编程序的一个限制是编译器的各种优化对其可能不起作用,这里时候就可以考虑改用内部指令。 内部函数看起来像一个普通的函数调用,但它实际上是编译器识别的内置函数。内部函数编译为内联代码,作为单个指令或作为一小段指令序列,一般用双下划线 (__) 标记 针对内部函数,ARM的CMSIS软件包也是做了一大批,主要分两类:
1、一类是CPU使用的内部函数,部分截图:
像NOP空周期指令,用到的地方很多。
需要硬件开平方指令,可以使用__sqrtf,开方操作仅需要12-14个时钟周期。
需要调节字节顺序,可以使用__REV, __REV16, __REVSH, __RBIT,这比我们用C来实现,方便太多了,而且速度快肯定,因为是直接调用的M内核专用指令
又比如各种RTOS里面最高优先级任务查找,调用指令CLZ(Count Leading Zeros)可以很快查找当前就绪的最高优先级任务(32个优先级)。
2、另一类是SIMD指令,这个在CMSIS-DSP库里面被大量应用,主要使用操作加速,下面是部分截图:
四、嵌入式汇编:
现在xxxx.S启动文件和各种RTOS的Port移植,都是采用的汇编文件(或者内联汇编)实现。像RTOS里面,做上下文切换得用汇编来做入栈和出栈处理。
不可否认,汇编用的比较溜,相比C有不错的速度优势。但是需要较深的汇编编程能力,这个时候可以多积累些好用的汇编代码。特别是一些算法类的加速和中断服务程序的快速执行。
比如uCOS做的CRC汇编,在需要软件CRC场景下,实际测试比市面上的各种C实现CRC加速都要有优势。
uC-CRC-master.zip
而且做成了C接口形式,大大方便大家使用,部分截图:
五、总结:
刚开始阶段可以先用ARM,各IC厂家和软件厂商提供的各种玩法,用熟练了,慢慢积累形式自己的风格。
针对这几种用法,ARM也做过一个简单对比图: