在保存和检索机制之间拥抱命令的代码

时间:2018-01-09 23:40:51

标签: c arm stm32 cpu-registers

最近,我正在c库中实现STM32F0系列mcu的内部外设。

当我看到ST如何设法对他们的HAL库做同样的事情时,我进入了这段代码......

  1 /*--------------------- EXTI Mode Configuration ------------------------*/
  2 /* Configure the External Interrupt or event for the current IO */
  3 if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) 
  4 {
  5  /* Enable SYSCFG Clock */
  6  __HAL_RCC_SYSCFG_CLK_ENABLE();

  7  temp = SYSCFG->EXTICR[position >> 2];
  8  CLEAR_BIT(temp, (0x0FU) << (4U * (position & 0x03U)));
  9  SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4U * (position & 0x03U)));
  10 SYSCFG->EXTICR[position >> 2] = temp;

  11 /* Clear EXTI line configuration */
  12  temp = EXTI->IMR;
  13  CLEAR_BIT(temp, (uint32_t)iocurrent);
  14  if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
  15  {
  16   SET_BIT(temp, iocurrent); 
  17  }
  18  EXTI->IMR = temp;

我想要了解的是为什么使用 7-10 12-18 行中的对命令。 为什么?为什么要存储一些内容然后写入然后从内存中删除它的内容? 它是关于多任务处理和竞争条件的吗?我不完全明白!

3 个答案:

答案 0 :(得分:3)

这用于速度优化并避免内存映射寄存器中的不需要的状态 想象一下示例内存映射变量EXT-&gt; ABC。想象一下这种夸张的例子情况:

  • 我们有一些可通过内存映射EXT-> ABC变量
  • 访问的硬件内存地址
  • 我们知道在EXT-&gt; ABC
  • 中设置了位1并清除了位2
  • 我们要清除第1位并设置第2位,并在EXT-> ABC
  • 中保持所有其他位不变
  • 硬件不允许EXT-&gt; ABC寄存器中的位1和位2清零或同时设置。这些状态是被禁止的,可能导致未定义的行为(这意味着在任何行为中,例如软件重置)。
  • 读取和写入EXT-&gt; ABC寄存器非常慢。

如果我们直接操作EXT-&gt; ABC变量:

CLEAR_BIT(EXT->ABC, 1); // expands to: EXT->ABC = EXT->ABC & ~1;
SET_BIT(EXT->ABC, 2);   // expands to: EXT->ABC = EXT->ABC | 2;

这将导致两条线之间出现禁止状态,因为将设置第1位和第2位。而且,在这两行中,EXTI-> IMR被访问4次。 为了解决这个问题,我们需要将值存储在某个地方的EXTI-> IMR寄存器中,修改所需的位,然后将修改后的值写入EXTI-&gt; IMR寄存器。所以我们会:

uint32_t temp;
temp = EXT->ABC; // store
CLEAR_BIT(temp, 1);
SET_BIT(temp, 2);
EXT->ABC = temp; // write

我们从内存映射变量中读取一次,修改并播放该值,执行我们想要的任何操作。之后,我们将一次写入内存映射变量。这样,EXT-> ABC寄存器只触摸两次,代码被安全写入,因此不会出现未定义/禁止/不需要的状态。
例如:对于第7-10行:要访问SYSCFG->EXTICR[position >> 2U],您需要多个cpu操作(计算position >> 2U,多个sizeof(SYSCFG->EXTICR),添加到SYSCFG->EXTICR地址,取消引用)。也许是开发人员打算更快地执行这些行。或者,您需要在写入0x0F<<(4*(position&0x03)时清除位(GPIO_GET_INDEX(GPIOx))<<(4*position&0x03)

答案 1 :(得分:2)

使操作“原子化”。在一次写操作中对寄存器的所有更改。

答案 2 :(得分:1)

我看不到任何奇怪的事情:

第7-10行和第12-18行将寄存器的内容复制到局部变量,对其执行某些操作,然后将结果存储回原始寄存器。

可能发生这种情况的原因有多种,但我的猜测是代码的作者不希望MCU在修补寄存器时处于中间状态。

例如,第8行之后但第9行之前的核心会发生什么?