使用结构集中硬件抽象层使代码执行速度变慢

Using structs to centralize the hardware abstraction layers make the code execution slow

我正在尝试使用该结构来集中我的硬件配置。但是,当结构被定义为 RAM 中的全局变量时,这会使我的代码稍后变慢。

比如我已经定义了

typedef struct
{
    PeriphBus       TIM_Bus;
    uint32_t        TIM_Clk;
    uint16_t        TIM_Prescaler;
    uint32_t        TIM_CounterMode;
    uint32_t        TIM_Autoreload;
    uint32_t        TIM_ClockDivision;
    uint32_t        TIM_RepetitionCounter;
    TIM_TypeDef     *TIM_Peripheral;
    IRQn_Type       TIM_Interrupt;
    uint32_t        TIM_IPeriority;
} TIMHandler;

TIMHandler  TIMCCS = {
    .TIM_Bus                        = APB1,
    .TIM_Clk                        = LL_APB1_GRP1_PERIPH_TIM2,
    .TIM_Prescaler                  = (10000 - 1),
    .TIM_CounterMode                = LL_TIM_COUNTERMODE_UP,
    .TIM_Autoreload                 = (1000 - 1),
    .TIM_ClockDivision              = LL_TIM_CLOCKDIVISION_DIV1,
    .TIM_RepetitionCounter          = 0,
    .TIM_Peripheral                 = TIM2,
    .TIM_Interrupt                  = TIM2_IRQn,
    .TIM_IPeriority                 = 2,
};

稍后在代码中,我尝试使用此代码重置中断标志。

void TIMCCS_IRQHandler (void)
{
    ... // some codes here are deleted to keep it simpler.
    LL_TIM_ClearFlag_UPDATE (TIMCCS->TIM_Peripheral);
}

不幸的是,最后一个重置中断标志的函数被延长了,而如果我将它替换为

LL_TIM_ClearFlag_UPDATE (TIM2);

恢复正常。

我想知道我在哪里犯了错误。我使用 ARM GCC 作为 STM32F7 微控制器的编译器。

我的第一个建议是查看两个版本代码之间生成的汇编代码。它在做你认为的事情吗?

下一个问题,你有没有打开优化器?

对我来说,乍一看,一个比另一个运行得慢是有道理的。如果您查看第一个版本,ISR 需要加载全局结构的地址。然后它需要取消引用该地址以获取存储在 TIM_Peripheral 变量中的值。然后将该值传递给 ClearFlag 函数。而第二个版本只是直接传递该值,跳过所有内存访问。但同样,汇编代码是你的朋友。

本文以热门评论开头...

I think it's not a type issue, it's how the memory mapping and addressing works.

不,它类型问题。如果传递给函数的类型是正确的,问题就会得到解决。继续阅读解决方案 ...

Precisely the "LL_TIM_ClearFlag_UPDATE(&TIMCCS->TIM_Peripheral)" works but with an excessive delay which is not acceptable to my case.

那么,换句话说,它起作用。请参阅下面的完整分析原因。

I mean "LL_TIM_ClearFlag_UPDATE(TIM2)" is faster and I was expecting to find a way to generate the same assembly code for both cases.

那是因为这个代码是正确的。您使用 TIMCCS 的代码 不是 等价物 [并且 错误 ]。

函数定义如下:

/**
  * @brief  Clear the update interrupt flag (UIF).
  * @rmtoll SR           UIF           LL_TIM_ClearFlag_UPDATE
  * @param  TIMx Timer instance
  * @retval None
  */
__STATIC_INLINE void LL_TIM_ClearFlag_UPDATE(TIM_TypeDef * TIMx)
{
    WRITE_REG(TIMx->SR, ~(TIM_SR_UIF));
}

参数必须是指向TIM_TypeDef结构的指针。显然,TIM2就是这样一个指针[因为它正在编译并且是working]。

struct 中,SR 元素是一个 uint16_t,它是一个端口地址。该代码清除 SR 指定的寄存器中的 TIM_SR_UIF 位。

当您作为参数传入时:&TIMCCS->TIM_Peripheral不是传递TIM_TypeDef *指针。

您传递的是 TIMCSS 结构本身的地址,不是 TIM_Peripheral 指向的地址。

因此,您将垃圾指针值传递给函数。因此,该函数将索引超过结构的末尾并获取 任何 16 位值恰好位于 SR.

的偏移处

这有两个[坏]影响:

(1) 该函数将清除寄存器端口 space 中某些 随机 位置的位。这 可能 造成一些严重的损害,这取决于实际使用的端口地址。由于处理器没有发出嘶哑的声音,因此它具有一些微妙的效果。

(2) 因为端口地址错误,所以会不会实际清除中断标志正确的中断控制器端口!

因此,当您从 ISR 中 return 时,中断( 被清除)将立即 重新中断处理器。

您将[再次]进入 ISR 并且[再次]不会清除正确的中断位。并且,当 ISR returns 时,处理器会立即重新中断。

这个循环会不断重复。

所以,你被锤击[无限]许多虚假中断!

基础级代码[即拼命试图取得进展]可能在中断再次发生之前执行一条指令。所以,它会取得一些[极其缓慢]的进展。

因此,对于执行的每条基本级指令,enter/exit ISR 需要执行 [可能] 10 [或更多] 条指令。

因此,结果是该过程看起来很慢(慢 10 倍到 100 倍)。

再一次,那是因为你对函数的调用不正确

正如我所说,您想要传递给函数的是TIM_Peripheral成员的内容你的 TIMCSS 结构。请记住这一点:您将 TIM2 的值作为初始化程序设置到该成员中。而且,我们知道 TIM2 是正确的值。

要正确使用您的结构实例,您需要:

LL_TIM_ClearFlag_UPDATE(TIMCCS.TIM_Peripheral);

旁注:

这个代码片段应该看起来很熟悉,因为我在我的热门评论中给出了它,基于正确的 c 代码。

你没有回答我提出的问题 [这会帮助你解决问题],而是选择“专注”你的分析,我在最热门评论中提到过 had 是错误的 [并给出了原因]。

事实上,我的第一个评论给出了正确的解决方案。