如何在寄存器中设置位?

时间:2013-02-07 07:57:41

标签: c registry bit memory-address

有注册表的地址(第一个?)SPI1。 有结构有偏移。我想这意味着 SPI1_REG_BASE + offset =某些SPI注册表的地址

#define SPI1_REG_BASE         (0x01F0E000)
//-----------------------------------------------------
//Register Structure & Defines
//-----------------------------------------------------
typedef struct
{
  volatile uint32_t SPIGCR0;        // 0x0000
  volatile uint32_t SPIGCR1;        // 0x0004
  volatile uint32_t SPIINT;         // 0x0008
  volatile uint32_t SPILVL;         // 0x000C
  volatile uint32_t SPIFLG;         // 0x0010
  volatile uint32_t SPIPC0;         // 0x0014
  volatile uint32_t SPIPC1;         // 0x0018
  volatile uint32_t SPIPC2;         // 0x001C
  volatile uint32_t SPIPC3;         // 0x0020
  volatile uint32_t SPIPC4;         // 0x0024
  volatile uint32_t SPIPC5;         // 0x0028
  volatile uint32_t RSVD0[3];       // 0x002C
  volatile uint32_t SPIDAT0;        // 0x0038
  volatile uint32_t SPIDAT1;        // 0x003C
  volatile uint32_t SPIBUF;         // 0x0040
  volatile uint32_t SPIEMU;         // 0x0044
  volatile uint32_t SPIDELAY;       // 0x0048
  volatile uint32_t SPIDEF;         // 0x004C
  volatile uint32_t SPIFMT0;        // 0x0050
  volatile uint32_t SPIFMT1;        // 0x0054
  volatile uint32_t SPIFMT2;        // 0x0058
  volatile uint32_t SPIFMT3;        // 0x005C
  volatile uint32_t INTVEC0;        // 0x0060
  volatile uint32_t INTVEC1;        // 0x0064
} spi_regs_t;

有一些定义和指针* spi的定义

#define CSDEF0 (0x00000001) //bit 0
#define CSHOLD (0x10000000) //bit 28
spi_regs_t *spi = (spi_regs_t *)SPI1_REG_BASE; 

我误解了位的设置。例如,

spi->SPIDEF |= CSDEF0 //set 0 bit in the registry field 

据我所知,SPIDEF是SPI寄存器,偏移地址为4Ch
(0x01F0E000 + 0x4C)。但是为什么CSDEF0是0位? SPIDEF注册表中有一个字段CSDEF(0-7位)。这意味着7位CSDEF的地址是0x00000008吗?和5位有地址0x00000006?

但是为什么SPIDAT1注册表的CSHOLD字段的地址为0x10000000?

spi->SPIDAT1 |= CSHOLD  //set bit 28

SPIDAT1寄存器的偏移地址为3Ch(0x01F0E000 + 0x3C) 它确实有字段CSHOLD(第28位)

如何| =在这种情况下工作?

我会感激任何帮助找出......所有这些%)

4 个答案:

答案 0 :(得分:4)

我认为你误解了寄存器的地址和价值的概念。

当您说SPI1模块的CSDEF0寄存器位于地址0x01F0E000 + 0x4C时,您是对的(基于您给出的结构描述)。该地址永远不会改变,它由硬件设计定义。

现在使用以下语句,您不是在操作地址,而是操作寄存器的值:

spi->SPIDEF |= CSDEF0; //set 0 bit in the registry field 
spi->SPIDAT1 |= CSHOLD;  //set bit 28

|=运算符是按位OR和赋值运算符。它等同于以下内容:

spi->SPIDEF = spi->SPIDEF | CSDEF0; //set 0 bit in the registry field 
spi->SPIDAT1 = spi->SPIDAT1 | CSHOLD;  //set bit 28

由于CSDEF0被定义为0x00000001,所以在第一个语句中,您有效地设置SPIDEF寄存器的LSB位,将所有其他位保留为其原始值。

答案 1 :(得分:1)

  

但是为什么CSDEF0是0位?

因为:

#define CSDEF0 (0x00000001) //bit 0

他们的意思不是“有0位的位”而是“0位的位”。

关于:

  

#define CSHOLD(0x10000000)//第28位

看看将hex-notation转换为二进制表示法,它将变得清晰。

  

如何| =在这种情况下工作?

1位 AT 这些位置(0和28)或'成为该变量之前的值。

答案 2 :(得分:1)

但为什么CSDEF0是0位

该宏的目的是将bit-0设置为1.如果该宏与任何寄存器进行“或”运算,则该寄存器的bit-0设置为1.

例如

让我们来spi->SPIDEF = 0x050A,即0x050A ==> 0000 0101 0000 1010

现在使用CSDEF0设置spi-> SPIDEF的第0位。

0x050A     ==> 0000 0101 0000 1010 
CSDEF0     ==> 0000 0000 0000 0001
               --------------------

spi->SPIDEF ==> 0000 0101 0000 1011

为什么SPIDAT1注册表的CSHOLD字段的地址为0x10000000?

同样如何使用CSDEF0表示第0位,CSHOLD用于第28位。

我猜你混淆了Hexa-deciamal和二进制表示0x000001和000001(???)。

0x01 is 01. 
0x02 is 10. 
0x100 is 1 0000 0000 
0x1000 is 1 0000 0000 0000 
0x10000000 is 1 0000 0000 0000 0000 0000 0000 0000
              ^-- Bit 28 starting from bit-0

答案 3 :(得分:1)

比特没有个人地址。

相反,嵌入式世界中的常见做法是将几个小属性连接到更大的寄存器。例如可以将实时调度程序的一些内部定义为:

   31 30 29 28 27     26 25 24 32 22     21 20 19     18          0
 [ max_priority  ] [ current_priority] [ reserved]   [  address_xxxx ]

这里max_priority是5位无符号整数,其值为0-31; 也可以将max_priority0定义为该值的最低有效位。所有这些参数都将在相同的绝对地址(REG_BASE + offset)内访问。