右移 28 位的操作用于确定标志位属于 SR1 寄存器还是 SR2 寄存器。这个技巧的背景是寄存器标志位的掩码值在位掩码定义中已经进行了编码,其中高 4 位(即右移 28 位后的结果)指示了标志位属于哪个寄存器。下面是详细解释:
标志位和寄存器的映射
在你提供的寄存器标志定义中,标志位被分配到两个不同的寄存器:
SR1 寄存器:包含如 I2C_FLAG_SMBALERT、I2C_FLAG_TIMEOUT 等标志。
SR2 寄存器:包含如 I2C_FLAG_DUALF、I2C_FLAG_SMBHOST 等标志。
在这些定义中,标志位的掩码值通常具有不同的位位置,这些位位置能够指示标志位是来自 SR1 还是 SR2。例如:
/* SR1 register flags */
#define I2C_FLAG_SMBALERT ((uint32_t)0x10008000)
#define I2C_FLAG_TIMEOUT ((uint32_t)0x10004000)
#define I2C_FLAG_PECERR ((uint32_t)0x10001000)
#define I2C_FLAG_OVR ((uint32_t)0x10000800)
#define I2C_FLAG_AF ((uint32_t)0x10000400)
#define I2C_FLAG_ARLO ((uint32_t)0x10000200)
#define I2C_FLAG_BERR ((uint32_t)0x10000100)
#define I2C_FLAG_TXE ((uint32_t)0x10000080)
#define I2C_FLAG_RXNE ((uint32_t)0x10000040)
#define I2C_FLAG_STOPF ((uint32_t)0x10000010)
#define I2C_FLAG_ADD10 ((uint32_t)0x10000008)
#define I2C_FLAG_BTF ((uint32_t)0x10000004)
#define I2C_FLAG_ADDR ((uint32_t)0x10000002)
#define I2C_FLAG_SB ((uint32_t)0x10000001)
/* SR2 register flags */
#define I2C_FLAG_DUALF ((uint32_t)0x00800000)
#define I2C_FLAG_SMBHOST ((uint32_t)0x00400000)
#define I2C_FLAG_SMBDEFAULT ((uint32_t)0x00200000)
#define I2C_FLAG_GENCALL ((uint32_t)0x00100000)
#define I2C_FLAG_TRA ((uint32_t)0x00040000)
#define I2C_FLAG_BUSY ((uint32_t)0x00020000)
#define I2C_FLAG_MSL ((uint32_t)0x00010000)
右移 28 位的原理
通过右移 28 位,你可以确定一个标志位的高 4 位。这些高 4 位用于区分标志位所属的寄存器。例如: • 如果高 4 位是 `0x1`,标志位属于 `SR1`。 • 如果高 4 位是 `0x0`,标志位属于 `SR2`。 这个逻辑是基于以下几个假设: 1. 标志位掩码 在 `SR1` 和 `SR2` 寄存器的位定义中具有不同的高位模式。 2. 寄存器偏移:`SR1` 和 `SR2` 寄存器的地址偏移量不同,这使得你可以通过计算寄存器地址来确定标志位的寄存器。
示例
假设 `I2C_FLAG` 是 `0x10000040`,这意味着标志位属于 `SR1` 寄存器。
uint32_t i2creg = I2C_FLAG >> 28; // 右移 28 位
// i2creg = 0x1,表明标志位属于 SR1 寄存器
反之,假设 I2C_FLAG
是 0x00800000
,这意味着标志位属于 SR2
寄存器。
uint32_t i2creg = I2C_FLAG >> 28; // 右移 28 位
// i2creg = 0x0,表明标志位属于 SR2 寄存器