我正在使用 ESP32 和 C 通过 SPI 与外部组件通信。 该组件可通过 255 个 24 位寄存器进行配置。 问题是有时我只需要翻转寄存器中的单个位并保持(寄存器的)其余部分不变,但我只能写入整个寄存器。
我看到了两种解决方案的可能性,但都不能令人满意:
uint32_t[255]
或类似的东西中跟踪寄存器。这看起来很浪费,而且容易出错,因为它重复信息并且可能不同步。执行此操作的首选方法是什么,或者我缺少更优雅的解决方案吗?
在大多数情况下,很大一部分寄存器被设置一次并且从未更改或根本没有显式设置(默认值),并且在许多情况下,如果整个寄存器不是由位组成,则可以在不参考当前值的情况下写入整个寄存器- 字段。 在某些情况下,寄存器可能会在程序的控制范围之外发生变化,并且在其中一部分情况下,写入这些寄存器可能对某些或所有位(只读位)没有影响。
因此,确实没有适合所有情况的单一解决方案,您最好实施以下所有内容:
并使用适合特定注册和应用要求的任何一个。
使用缓存修改写入而不是缓存整个寄存器文件,您可以在每个寄存器的基础上执行此操作。鉴于说:
typedef struct
{
uint8_t adr ;
uint8_t cache ;
bool cached ;
} tCachedReg ;
uint8_t cachedWriteBits( tCachedReg* reg, uint8_t msk, uint8_t Val )
{
if( !cached )
{
reg.cache = readReg( reg.adr ) ;
}
reg.cache = (reg.cache & ~msk) | (val & msk) ;
writeReg( reg.adr, reg.cache ) ;
return reg.cache ;
}
然后您可以编写如下代码:
tCachedReg somereg = { 0xA5 } ;
// Clear MSB
cachedWriteBits( &somereg, 0x80, 0 ) ;
在第一次写入中,这将是读取-修改-写入,随后它将使用缓存的值。 如果寄存器要在第一次写入时完全初始化,您可以通过初始化
tCachedReg
来避免初始读取,例如:
tCachedReg somereg = { 0xA5, 0x55, true } ;
// Clear MSB
cachedWriteBits( &somereg, 0x80, 0 ) ;
在这种情况下,第一次写入时,寄存器将被写入 0x55。
它非常灵活,但您必须注意不要将缓存修改写入与读取修改写入或对同一寄存器的无条件写入组合起来,而不修改缓存。 就我个人而言,我会使用 C++ 来实现此目的,并将所有三个方法包装到一个类中,无论如何都维护缓存,但您也可以在 C 中执行此操作,但不太干净。