最近,我正在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 行中的对命令。 为什么?为什么要存储一些内容然后写入然后从内存中删除它的内容? 它是关于多任务处理和竞争条件的吗?我不完全明白!
答案 0 :(得分:3)
这用于速度优化并避免内存映射寄存器中的不需要的状态 想象一下示例内存映射变量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行之前的核心会发生什么?