微型滚轮中的内存映射

时间:2016-08-25 08:13:12

标签: c arm

OnNavigatedTo

这是ARM微控制器中使用的存储器映射定义

结构定义

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    //if the mainpage resource exists then load the container
    if (Application.Current.Resources.ContainsKey("mainpage"))
    {
        var resource = Application.Current.Resources["mainpage"];
        myCanvas.InkPresenter.StrokeContainer = (InkStrokeContainer)resource;
    }
}
//I save the StrokeContainer in a button click event
private void myBtn_Click(object sender, RoutedEventArgs e)
{
    Application.Current.Resources.Add(new KeyValuePair<object, object>("mainpage", myCanvas.InkPresenter.StrokeContainer));
}
  1. (dual_timers *)0x03FF6000)的含义是什么?是类型转换。 如果是类型转换,请在代码中解释它的影响。

  2. 编译器如何在此之后看到定义'定时器'?

3 个答案:

答案 0 :(得分:3)

这里有无数次被问到并回答过。

首先关闭结构的东西是一个坏主意,不便携不可靠,即使它经常被使用,因为它不在供应商代码中。很少有时间炸弹等着你去支付他们的支持。

你的定义只是基本的C.它是一个类型转换,我有这个地址恰好是硬编码的,在C编程类中我们可能已经使用了一些其他指针的名称而可能不是定义

unsigned int *bob;
unsigned char *ted = (unsigned char *)bob;

(你应该永远不要使用另一种编程技巧)。你可以将它作为定义旋转

#define ted (unsigned char *)bob

或者那种效果。 bob只是一个具有人类可读名称的地址。

为了使这个工作,你需要一个volatile(它不是吗?)并且他们还有另一个typedef定义了dual_timers,因此他们不必继续输入volatile unsigned int或volatile uint32_t或volatile uint8_t或者寄存器的大小是。 volatile是因为你知道,但是编译器没有指出硬件而不是ram,你需要编译器执行所有的加载和存储而不是优化任何输出。

此外,您需要编译器执行正确大小的加载和存储,如果它是只能通过32位宽事务访问的寄存器,则需要编译器使用正确的指令实现此操作。无论你做什么都不是保证,这种编程风格如果你运气不好就会失败。这是一种非常广泛的实践,但它并非万无一失。它甚至比指向绝对地址更糟糕的是在编译域中使用结构,硬件是代码中的单独编译域。无论您找到多少编译器特定指令,您都无法保证该代码将随着时间的推移而继续工作并且编译器升级或者如果上帝禁止您尝试在其他计算机上编译。它可能在99.9999%的时间内起作用,但它失败的那个时间是一次大规模的失败,这次地震曾在无数年内摧毁了整个东京。正如您在使用抽象的内核驱动程序中看到的那样,使用可移植代码,在裸机中,您可以使用汇编语言实现该抽象,并保证使用正确的指令。它可能会花费你一些周期,所以你可以创建一个define / typedef,就像你要求抽象的那样,但你的代码不会强制进入,如果你需要你的代码就不需要完全重写移植代码或解决芯片勘误等问题。后者是我个人的观点和风格,基于数十年的裸机编程经验。

define只是一个基本的C typedef没有什么特别的或花哨的只是读它就像任何其他C语法一样来理解它在做什么。结构是一种向该地址应用偏移的方法,因此如果我们假设所有这些寄存器都是32位,则“欲望”是对TMOD的访问在地址0x03FF6000 + 0x00,对TDATA0的访问在地址0x03FF6000 + 0x04,TDATA1 0x03FF6000 + 0x08等等没有。但是,这里没有任何东西确保实际发生,也不确保使用32位加载或存储。对代码的简单反汇编将显示为这些访问生成的这些地址。

我假设你尝试使用这样的代码来看看它做了什么:

typedef volatile unsigned int special_register;
typedef struct
{
    special_register TMOD;
    special_register TDATA0;
    special_register TDATA1;
    special_register TCNT0;
    special_register TCNT1;
} dual_timers;
#define timers ((dual_timers *)0x03FF6000)
unsigned int fun ( void )
{
    timers->TMOD=5;
    timers->TDATA0|=1;
    timers->TCNT0=timers->TCNT1;
    return(timers->TDATA1);
}
如你所提到的那样

用于生产

00000000 <fun>:
   0:   e3a02005    mov r2, #5
   4:   e59f301c    ldr r3, [pc, #28]   ; 28 <fun+0x28>
   8:   e5832000    str r2, [r3]
   c:   e5932004    ldr r2, [r3, #4]
  10:   e3822001    orr r2, r2, #1
  14:   e5832004    str r2, [r3, #4]
  18:   e5932010    ldr r2, [r3, #16]
  1c:   e583200c    str r2, [r3, #12]
  20:   e5930008    ldr r0, [r3, #8]
  24:   e12fff1e    bx  lr
  28:   03ff6000    mvnseq  r6, #0

答案 1 :(得分:0)

是的,它是类型转换。它基本上表示从地址0x03FF6000开始,您可以认为存在dual_timers结构。

在这种情况下,我猜special_register被定义为volatile unsigned uint32_t

这是一种轻松访问微控制器寄存器的典型方法。例如,要访问注册表TDATA0,您需要在代码中使用timers->TDATA0

答案 2 :(得分:0)

这意味着有一个指向结构dual_timers的指针,指针的值为0x03FF6000,即它指向位于0x03FF6000的结构。

编译器(实际上是预处理器)每次查看单词(dual_timers *)0x03FF6000)时都会看到表达式timers。对于您来说,它看起来像timers->TDATA0,但对于编译器,它看起来像(dual_timers *)0x03FF6000)->TDATA0,取TDATA0位于dual_timers的{​​{1}}结构的0x03FF6000字段。