开源改变世界

简化中断 #1047

推推 grbl 2年前 (2023-01-23) 143次浏览

关闭
J-Dunn 打开了这个问题 2016 年 7 月 29 日 · 18条评论
关闭

简化中断#1047

J-Dunn 打开了这个问题 2016 年 7 月 29 日 · 18条评论

注释

简化中断 #1047

当前的计时器设置工作正常并且经过了很好的测试,但我想知道是否可以简化它从而加快速度。

是否有需要固定持续时间 STEP 脉冲的受支持驱动程序硬件上下文,或者这是否可以减少到更灵活的条件,即断言 STEP 的最短时间?

谢谢。

简化中断 #1047

我不明白为什么任何硬件都需要最少的时间,但是随着中断时间接近步进时间,您会用完“关闭”时间。
同样,中断提供了一些选项来增加从设置方向到步进脉冲的延迟,一些硬件可能需要

可以在步进中断结束时设置方向,但随后又回到“关闭”时间用完

简化中断 #1047

是否有特定的理由来改变正在工作的东西?任何变更都存在风险。

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 30 日  

“是否有特殊原因来改变有效的方法?”

这是作为移植到 STM32 的一部分出现的,其中不同的中断结构意味着它无论如何都会被改变。我将问题发布在这里作为数百种不同机器硬件配置的相关知识所在的地方。

我的猜测与 langwadt 所说的相同,但这可能只是我对某些可能的排列和要求缺乏了解。

简化中断 #1047
USBCNC 评论了 2016 年 7 月 30 日  

@J-Dunn,如果你想实验定时器,你可以试试Windows模拟项目。这将对您了解其工作原理有很大帮助。我现在正在用它来分析定时器,看看是否有可能优化定时器,甚至把 s 曲线放到 GRBL 上。Windows 模拟可以帮助您在没有硬件的情况下运行和调试代码。
我首先要做的是查看是否可以为每个计算的计时器删除 srqt 函数。后来我可能只想使用整数来计算圆。无需使用浮点数和sin cos函数,不仅节省了时间,而且节省了大量的代码空间。

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 31 日  

What I am trying to do first to see if it is possible to remove the srqt function for each timer calculated.
很难看出在这种计算中如何避免对 sqrt 的需要。我认为可能值得考虑在 AVR 上使用泰勒级数展开来达到所需的精度,但我怀疑在带有 FPU 的 32b 硬件上是否需要它。

sqrt() 是一个相当复杂的计算,你在STM32F4上计时了吗?

3.10.26
VSQRT
浮点平方根。

我无法找到它需要的时钟周期数,但我认为在具有特定指令的硬件上运行时担心从 GRBL 中消除 sqrt 没有多大意义。

简化中断 #1047

我在 100MHz STM32M4 上粗略地计时了一个 sqrt(float),它需要 ~10us,数学库不使用 FPU 指令可能是严格符合 IEEE 标准?

asm 指令 vsqrt.f32 需要 14 个周期,所以 140ns

将 sqrt() 重新定义为使用 vsqrt.f32 的函数似乎在快速测试中没有破坏任何东西

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 31 日  

哇,快了两个数量级。我假设如果 FPU 有 sqrt 指令就会被使用。可能最好将其定义为内联宏,而不是添加 fn 调用的开销。

它主要用于不太重要的计划阶段,但如果它在那里似乎值得使用。

如果在 STM32 上需要 10us,那么在 AVR 上必须至少为 60us。

限制.c:
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.

看起来 sqrt 是 200us 的重要部分。这可能值得用 AVR 上的四项泰勒级数展开来代替。这可能会将 sqrt 减少到几个 us。

简化中断 #1047
作者

数学库不使用 FPU 指令可能是严格符合 IEEE 标准?

我发现来自 ST 的勘误表说如果在 14 个周期完成之前返回的 ISR 中使用 VSQRT 会出现问题。这可能是不在 IEEE 上下文中使用它的原因。

简化中断 #1047

我想我找到了原因,AVR-GCC 有一个怪癖,即 float 和 double 是相同的,所以使用 sqrt(double) 而不是 sqrtf(float) 并不重要,它们调用相同的函数

在 ARM 上,float 是 32 位,double 是 64 位,所以当使用 sqrt() 时,使用了可以处理 64 位的冗长的 lib 函数,sqrtf() 编译为单个 vsqrt.f32 指令,除了 -O0

为了移植代码,可能应该更改为显式使用浮点函数的浮点版本,即 sinf、cosf、fabsf 等。

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 31 日  

感谢 langwadt,只是为了完整性 CMSIS 似乎没有使用 sqrtf() 但它有自己的 fastmath 库和 arm_sqrt_q15() 等。即。

最干净的方法是在头文件中重新定义 sqrt() 而不是编辑所有 sqrt() 调用或使用 #define 并使代码混乱吗?

#define sqrt sqrtf // 在 Cortex 上使用 FPU vsqrt.f32

??

简化中断 #1047

更简单,在 grbl.h 中用 tgmath.h 替换 math.h 它知道类型并调用正确的函数

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 31 日  

谢谢,我不知道那个标题。用它建造的建筑使精灵的体型减少了大约 600b。

但是,它似乎并没有给我一个 VSQRT :


080170d4 <sqrtf>:
 80170d4: b510        push  {r4, lr}
 80170d6: ed2d 8b02   vpush {d8}
 80170da: 4c29        ldr r4, [pc, #164]  ; (8017180 <sqrtf+0xac>)
 80170dc: b08a        sub sp, #40 ; 0x28
 80170de: eef0 8a40   vmov.f32  s17, s0
 80170e2: f000 fb23   bl  801772c <__ieee754_sqrtf>

sqrtf() 编译为单个 vsqrt.f32 指令

我似乎不明白。在 stepper.c 中使用上面的宏,我仍然以 __ieee754_sqrtf 结束,我错过了什么?

简化中断 #1047

尝试打开一些优化,比如 -OG

简化中断 #1047
成员

@J-Dunn: 仅供参考,AVR 上的浮点乘法不是那么快。每次浮点数乘法需要 9-10us(浮点数除法更糟)。您可能会通过使用泰勒展开得到更多的循环,但我对它的近似值引起的误差以及我如何使相关计算不稳定保持警惕。当你做那样的事情时,你必须非常小心。也就是说,我认为不值得花时间和精力为 328p 在这里和那里收集更多的循环,因为它对大多数人来说运行正常。俗话说,如果它没有坏,就不要“修理”它。

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 31 日  

尝试打开一些优化,比如 -OG

不,可悲的是,它仍然以 __ieee754_sqrtf 结尾,如上所示:?

简化中断 #1047

如果你真的很想花时间优化事情,那么你应该使用类似的东西:https ://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m /。其他任何东西都在黑暗中刺伤。过去我曾多次沿着这条路走,几乎总是发现我认为有问题的地方实际上并不是问题所在。最后,我最好还是把精力花在添加功能上 :-( 然而,像你一样深入挖掘是一种很好的教育体验。

简化中断 #1047
作者
J-邓恩 评论了 2016 年 7 月 31 日  

正如我在上面的#4中指出的那样,这里的重点是移植到 STM32,问题是任何支持的硬件是否需要固定的脉冲周期,而不是简单的断言 STEP 的最小周期。

如果下降沿不需要“准时”发生,它会大大简化 ISR。但可能有一些驱动硬件使用下降沿。或许 Sonny 可以对此发表评论。

简化中断 #1047
作者
J-邓恩 评论了 2016 年 8 月 1 日  

         prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters);
 8011fc4: edd3 7a09   vldr  s15, [r3, #36]  ; 0x24
 8011fc8: ee77 7aa7   vadd.f32  s15, s15, s15
 8011fcc: ee67 7a87   vmul.f32  s15, s15, s14
 8011fd0: ee76 7ae7   vsub.f32  s15, s13, s15
 8011fd4: eeb1 0ae7   vsqrt.f32 s0, s15
 8011fd8: eeb4 0a40   vcmp.f32  s0, s0
 8011fdc: eef1 fa10   vmrs  APSR_nzcv, fpscr
 8011fe0: d009        beq.n 8011ff6 <st_prep_buffer+0x186>
 8011fe2: edd3 7a09   vldr  s15, [r3, #36]  ; 0x24
 8011fe6: ee77 7aa7   vadd.f32  s15, s15, s15
 8011fea: ee27 0a87   vmul.f32  s0, s15, s14
 8011fee: ee36 0ac0   vsub.f32  s0, s13, s0
 8011ff2: f001 fd2b   bl  8013a4c <sqrtf>

啊,我想我找到了为什么 sqrtf 仍然在那里。由于 VSQRT 返回零错误(如负数的根)以及非错误的零结果,编译器必须回退到 IEEE754 代码周围的 sqrtf() 包装器以获得错误处理。所以它通常是非常快的 FPU 调用,但 sqrtf() 和 __ieee754_sqrtf() 代码仍然被编译进去。

这似乎与拥有严格且一致的错误处理流程有关,该流程符合 IEEE 标准。如果 VSQRT 返回一个有限的结果,那么它就会很快,否则它必须重新计算很长的路才能找出发生了什么。

喜欢 (0)