Nul*_*ion 2 embedded microcontroller arm low-level-io
之前面试的时候也遇到过这个问题,但是没有得到反馈。
由于它是一个寄存器,我是否需要在访问寄存器之前禁用中断以防止数据损坏?考虑使用两个缓冲区,32 位和 64 位,并将 32 位缓冲区发送到 read32() 中,并将其相应地转移到 64 位缓冲区。我们假设这是小端架构。
我在 repl.it 上编写了一个快速示例代码(输出与寄存器值不匹配)
#include <stdio.h>
#include <string.h>
#include <stdint.h>
void read32(uint64_t *reg, uint32_t *buffer){
memcpy(buffer, reg, 4);
}
int main(void) {
//register
uint64_t reg = 0xAAAAAAAAFFFFFFFF;
//buffers
uint32_t buf_32 = 0;
uint64_t buf_64 = 0;
//read LSW
read32(®, &buf_32);
buf_64 |= buf_32; //add LSW
//read MSW
read32(®+4, &buf_32);
buf_64 |= ((uint64_t)buf_32 << 32);
printf("64 bit register value: 0x%lx\n", buf_64);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
64 bit register value: 0x1ffffffff
Run Code Online (Sandbox Code Playgroud)
禁用中断不会阻止可能独立于代码序列而变化的 I/O 寄存器发生变化。
通常,当两个大于架构宽度的硬件寄存器之间需要数据一致性时,硬件数据表或参考手册将建议如何读取数据 - 通常通过指定必须读取寄存器才能与硬件一起工作的顺序使其“安全”的机制。
在其他情况下,该方法可能由寄存器的性质及其功能/行为决定。例如,如果您有两个 32 位定时器/计数器,其中一个溢出会触发另一个递增,形成一个 64 位计数器,那么很明显,只有当低位计数器溢出时,高位计数器才会改变。在这种情况下,您可以简单地读取低点,然后读取高点,如果低点已经包裹,则重复:
uint32_t low_word = 0, high_word = 0;
do
{
low_word = *low_reg_addr ;
high_word = *high_reg_addr ;
} while( *low_reg_addr > low_word ) ; // If low has wrapped, re-read
uint64_t full_word = (uint64_t)high_word << 32 | low_word;
Run Code Online (Sandbox Code Playgroud)
因此,如果在读取高位寄存器后低位寄存器没有换行,则数据必须一致,并且循环退出。如果已经换行,则数据可能不一致,必须重新读取。