简体   繁体   English

使用偏移量获取微控制器中寄存器的完整地址的目的是什么?

[英]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 to 0x4002.5FFF )and it's pins (using APB bus) 例如,配置端口F(从0x4002.50000x4002.5FFF开始)及其引脚(使用APB总线)

  1. Activate clk to this port by setting (bit 5) to 1 in RCGCGPIO register which it's Base address is 0x400F.E000 with Offset 0x608 so full address is 0x400FE608 通过将RCGCGPIO寄存器中的(位5)设置为1(基地址为0x400F.E000 ,偏移0x6080x400F.E000 ,使完整地址为0x400FE608 )来激活clk到该端口
  2. Configure the 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
  3. Configure the 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
  4. Configure the GPIODATA reg which it's base address is 0x4002.5000 with 0x3FC so full address is 0x4002.50x3FC 配置GPIODATA REG,它的基地址为0x4002.50000x3FC如此完整的地址是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? 使用偏移量是否会增加可读性,并使它变得简单易用,因为我们只需编写偏移量即可获得所需的寄存器?


Update 更新

I found that Base address has more usage than obtaining the full address of a register. 我发现基地址比获得寄存器的完整地址有更多用途。

for example : GPIODATA controls 0-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 on Port F we write to the address base 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. 缺点是执行开销很小,因为该地址必须在运行时计算。

  1. Because documentation is written this way. 因为文档是用这种方式编写的。

在此处输入图片说明

  1. But in the fact no one (except reinventers of the wheel) does it this way. 但事实上,除了轮子的发明者之外,没有人这样做。 STM CMSIS files define structures and compiler calculates the offsets itself: STM CMSIS文件定义结构,编译器自己计算偏移量:
      #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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM