[英]what is the purpose of using offset to get register full address in micro-controller?
I'm new to embedded systems programming, and trying to make my way. 我是嵌入式系统编程的新手,正在尝试自己的方式。 Using Stellaris LM4F120 LaunchPad Evaluation Board with datasheet
LM4F120H5QR Microcontroller
I found to get the full address of some registers you have always to add an offset! 我将Stellaris LM4F120 LaunchPad评估板与数据表
LM4F120H5QR Microcontroller
我发现要获得某些寄存器的完整地址,而您必须始终添加一个偏移量! which I don't get the importance of it as instead we can use the full address directly! 我不了解它的重要性,因为我们可以直接使用完整的地址!
For example to configure Port F (which starts from
0x4002.5000
to0x4002.5FFF
)and it's pins (using APB bus)例如,配置端口F(从
0x4002.5000
到0x4002.5FFF
开始)及其引脚(使用APB总线)
RCGCGPIO
register which it's Base address is 0x400F.E000
with Offset 0x608
so full address is 0x400FE608
RCGCGPIO
寄存器中的(位5)设置为1(基地址为0x400F.E000
,偏移0x608
为0x400F.E000
,使完整地址为0x400FE608
)来激活clk到该端口 GPIODIR
reg which it's base address is 0x4002.5000
with offset 0x400
so full address is 0x4002.5400
GPIODIR
reg,其基地址为0x4002.5000
,偏移量为0x400
因此完整地址为0x4002.5400
GPIODEN
reg which it's base address is 0x4002.5000
with offset 0x51C
so full address is 0x4002.551C
GPIODEN
reg,其基地址为0x4002.5000
,偏移量为0x51C
因此完整地址为0x4002.551C
GPIODATA
reg which it's base address is 0x4002.5000
with 0x3FC
so full address is 0x4002.50x3FC
GPIODATA
REG,它的基地址为0x4002.5000
与0x3FC
如此完整的地址是0x4002.50x3FC
If I can guess it would be the offset here is used to make it less prone to error as we can write it like this : 如果我能猜到它是偏移量,则可以使用它来减少出错的可能性,因为我们可以这样写:
#define GPIO_PORTF_BASE 0x40025000
#define GPIO_PORTF_DATA (*((volatile unsigned long *)(GPIO_PORTF_BASE + 0x3FC)))
#define GPIO_PORTF_DIR (*((volatile unsigned long *)(GPIO_PORTF_BASE + 0x400)))
#define GPIO_PORTF_DEN (*((volatile unsigned long *)(GPIO_PORTF_BASE + 0x51C)))
Does using offset increases readability and makes it easier and unsophisticated as We only have to write the offset to get the desired register? 使用偏移量是否会增加可读性,并使它变得简单易用,因为我们只需编写偏移量即可获得所需的寄存器?
I found that Base address has more usage than obtaining the full address of a register.
我发现基地址比获得寄存器的完整地址有更多用途。
for example :
GPIODATA
controls0-7 pins
and it has 255 registers that can allow us to configure each pin individually and even their combination just by adding an offset to the base address eg If we want to configure the Red Led which is onPort F
we write to the addressbase address 0x4002.5000 + offset 0x008
directly.例如:
GPIODATA
控制0-7 pins
,它具有255个寄存器,可以让我们仅通过向基地址添加偏移量就可以单独配置每个引脚,甚至可以配置它们的组合,例如,如果我们要配置Port F
上的红色LED我们直接写入地址base address 0x4002.5000 + offset 0x008
。
You could write #define GPIO_PORTF_DATA 0x400253FC
which gives you the absolute address of the data register of port F. Its only a macro and its easier for you as a programmer to know that you're talking about the data register of some port. 您可以编写
#define GPIO_PORTF_DATA 0x400253FC
,它为您提供端口F数据寄存器的绝对地址。它只是一个宏,对于程序员来说,它更容易使您知道您在谈论某个端口的数据寄存器。
The way I see at my work as an embedded programmer, you use offset in order to write less as possible the absolute address. 在我作为嵌入式程序员的工作方式中,您使用offset来尽可能少地写入绝对地址。
Some of the reasons that I can think about is when you find an error with the address, or you get new version of the hardware, or what ever happened that you have to write new driver with new addresses, and let assume the structre of the registers has'nt change but only the addresses, with offsets you only have to change the base address and not all the registers in your code. 我能想到的一些原因是,当您发现地址错误,或者您获得了新版本的硬件,或者曾经发生过必须使用新地址编写新驱动程序并假定结构为寄存器没有改变,只有地址,带有偏移量,您只需要更改基地址,而不是代码中的所有寄存器。
That's because the header you copied those definitions from is auto-generated from the CMSIS System View Description format . 这是因为您从CMSIS系统视图描述格式中自动复制了这些定义的标头。 This format is used by chip manufactures to describe the core and peripheral elements of their microprocessors in a standardized way.
芯片制造商使用此格式以标准化方式描述其微处理器的核心和外围元素。 Usually you can download those so called ".svd" files at some repository or at the manufacturers homepage.
通常,您可以在某些存储库或制造商的主页上下载那些所谓的“ .svd”文件。
One of those described peripherals of the LM4F120H5QR would be the general purpose IO port F (GPIOF). LM4F120H5QR所描述的那些外设之一将是通用IO端口F(GPIOF)。 The .svd file would contain an element for the port with some base-address and then a sub-element for every register the peripheral has with some offset.
.svd文件将包含具有一些基地址的端口元素,然后是外设具有一些偏移量的每个寄存器的子元素。
The specific code you posted doesn't make much sense. 您发布的特定代码没有多大意义。 But in the general case, you'd do something like this is to handle multiple hardware peripherals on the same chip:
但是在一般情况下,您将执行以下操作:在同一芯片上处理多个硬件外设:
#define PORTF 0x40025000ul
...
#define GPIO_PORT_DATA(base) (*((volatile unsigned long *)(base + 0x3FCul)))
#define GPIO_PORT_DIR(base) (*((volatile unsigned long *)(base + 0x400ul)))
#define GPIO_PORT_DEN(base) (*((volatile unsigned long *)(base + 0x51Cul)))
Given that all peripherals have the same memory mapping, you can now write a single driver which can handle multiple peripherals. 由于所有外围设备都具有相同的内存映射,因此您现在可以编写一个可以处理多个外围设备的驱动程序。 GPIO might not be the best example, since writing abstraction layers over GPIO usually just adds clutter.
GPIO可能不是最好的例子,因为通过GPIO编写抽象层通常只会增加混乱。 But in theory we could have this driver:
但从理论上讲,我们可以使用以下驱动程序:
void gpio_set (volatile unsigned long* port, uint8_t pin);
...
gpio_set (PORTF, 5);
Where gpio
doesn't know which specific port it is dealing with, it does the same job no matter, by accessing the macros. 如果
gpio
不知道它正在处理哪个特定端口,则无论如何,它都会通过访问宏来完成相同的工作。
This is a common way to write drivers for things like SPI, UART, CAN, ADC etc where you are likely to have several identical peripherals on-chip and want the same code to handle them all, without code repetition. 这是为SPI,UART,CAN,ADC等编写驱动程序的常用方法,在这些驱动程序中,您可能在片上拥有多个相同的外设,并希望使用相同的代码来处理它们,而无需重复代码。
The down side is a tiny bit of execution overhead, since the address must be calculated in run-time. 缺点是执行开销很小,因为该地址必须在运行时计算。
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.