TL; DR:
(unsigned long)(0x400253FC)
不等同于(unsigned long)((*((volatile unsigned long *)0x400253FC)))
?我正在使用ARM Cortex-M3处理器(TI的LM3S6965)及其StellarisWare(免费下载,出口控制)定义。我正在使用gcc版本4.6.1(Sourcery CodeBench Lite 2011.09-69)。 Stellaris在“inc / lm3s6965.h”中提供了大约5,000个寄存器和内存地址的定义,我真的不想重做所有这些。但是,它们似乎与我想写的宏不兼容。
在ARM Cortex-M3上,一部分内存别名为外设和RAM内存空间的每位32位字。将地址0x42000000的存储器设置为0x00000001会将地址0x40000000的存储器的第一位设置为1,但不会影响字的其余部分。要更改位2,请将0x42000004处的字更改为1.这是一个简洁的功能,非常有用。根据ARM技术参考手册,计算地址的算法是:
bit_word_offset = (byte_offset x 32) + (bit_number × 4)
bit_word_addr = bit_band_base + bit_word_offset
其中:
bit_word_offset
是位带内存区域中目标位的位置。bit_word_addr
是别名内存区域中映射到的字的地址
目标位。bit_band_base
是别名区域的起始地址。byte_offset
是包含目标位的位带区域中的字节数。bit_number
是目标位 "inc/hw_types.h"
文件包含以下实现此算法的宏。为了清楚起见,它为基于字的模型实现了它,它接受4字节对齐的字和0-31位的偏移,但结果地址是等价的:
#define HWREGBITB(x, b) \
HWREGB(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \
(((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
该算法采用SRAM中的基数为0x20000000或外围存储空间为0x40000000)并将其与0x02000000进行或运算,并添加位带基址偏移量。然后,它将偏移量与基数相乘32(相当于左移五位)并加上位数。
引用的HWREG只是执行必要的强制转换,以便写入内存中的给定位置:
#define HWREG(x) \
(*((volatile unsigned long *)(x)))
这与
这样的作业非常吻合HWREGBITW(0x400253FC, 0) = 1;
其中0x400253FC是内存映射外设的幻数,我想将此外设的第0位设置为1.上面的代码计算(在编译时,当然)位偏移并将该字设置为1
不幸的是,“inc / lm3s6965.h”中的上述定义已经执行了HWREG完成的转换。我想避免使用魔术数字,而是使用提供的定义,如
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
尝试将其粘贴到HWREGBITW会导致宏不再起作用,因为转换会干扰:
HWREGBITW(GPIO_PORTF_DATA_R, 0) = 1;
预处理器生成以下混乱(添加缩进):
(*((volatile unsigned long *)
((((unsigned long)((*((volatile unsigned long *)0x400253FC)))) & 0xF0000000)
| 0x02000000 |
((((unsigned long)((*((volatile unsigned long *)0x400253FC)))) & 0x000FFFFF) << 5)
| ((0) << 2))
)) = 1;
请注意
的两个实例(((unsigned long)((*((volatile unsigned long *)0x400253FC)))))
我相信这些额外的演员阵容是导致我的进程失败的原因。预处理HWREGBITW(0x400253FC, 0) = 1;
的以下结果确实有效,支持我的断言:
(*((volatile unsigned long *)
((((unsigned long)(0x400253FC)) & 0xF0000000)
| 0x02000000 |
((((unsigned long)(0x400253FC)) & 0x000FFFFF) << 5)
| ((0) << 2))
)) = 1;
(type)
强制转换操作符具有从右到左的优先级,因此最后一次强制转换应该应用,并且unsigned long
用于按位算术(然后应该正常工作)。在任何地方都没有任何隐含,没有浮动指针转换,没有精度/范围变化......最左边的转换应该简单地使转换无效到右边。
(unsigned long)(0x400253FC)
不等同于(unsigned long)((*((volatile unsigned long *)0x400253FC)))
?HWREGBITW
宏工作?或者,如果用一个预先存在的转换器给出一个参数,如何编写宏来执行相同的任务但不会失败?答案 0 :(得分:6)
1-为什么不(无符号长)(0x400253FC)等效于(无符号长整数)((*((volatile unsigned long *)0x400253FC)))?
前者是整数字面值,其值为0x400253FCul
,而后者是存储在(内存或GPIO)地址unsigned long
0x400253FC
值
2-如何使现有的HWREGBITW宏工作?或者,如何在执行相同任务时编写宏,但在给出与预先存在的强制转换的参数时不会失败?
改为使用HWREGBITW(&GPIO_PORTF_DATA_R, 0) = 1;
。