首页 文章

如何在STm32核板上写入SRAM(mbed)

提问于
浏览
-1

我想在芯片上的SRAM中存储一个简单的整数 . (Cortex M4)我使用的程序是在线进行的 . 我知道SRAM的地址从0x2000 0000开始,芯片有4KB的内存 .

我已经阅读了数据表和bitbanding部分,但它对我来说没有意义 .

有人可以向我解释如何存储例如SRAM中的数字5并再次读取它吗?

当前代码是这样的(c是用户通过按钮更改的整数):
if(c==100){ temp=c; MBX_B0 = 1; // Word write temp = MBX_B7; // Word read TIMER_B0 = temp; // Byte write return TIMER_B7; // Byte read } pc.printf("%d",temp);

它只是在c == 100时停止运行即使在掉电后也应该保存 .

2 回答

  • 3

    编辑,您的问题完全改变了答案,因为您对除了flash / eeprom之外的所有SRAM编写都不感兴趣...

    因此,在此答案中添加一个主要部分,您的评论至关重要:

    但即使断电后值是否仍然存储?这不是SRAM会做什么而不是普通的RAM? RAM =无电源时丢失值,SRAM =无电时保持值?

    SRAM表示静态RAM,RAM表示随机存取存储器 . 现在RAM的定义可以安全地用于像ROM(只读存储器)这样的东西,因为随机部分与寻址有关,我可以寻址任何我想要的随机地址,或者我只能使用线性一个地址来读取这个东西另一些规则 .

    惯例是ROM是非易失性的,RAM是易失性的,这是相关术语 . ROM实现在技术上不是只读的PROM是可编程的ROM,这意味着可写,因此有点打破了EPROM电可编程术语,EEPROM是电可擦除和可编程的 . 闪存是一种较新的技术,可电擦除和可编程ROM或非易失性存储 .

    在这种意义上的易失性意味着它能够或不能在电源循环中存活 . volaitle意味着它不能非易失性意味着它可以 .

    SRAM中的S用于静态确定,这个术语暗示它可能在esp中存活,当你学习DRAM时,D意味着动态,并且完全可以假设一个在电源循环中存活而另一个不是,但不幸的是,这不是他们所指的 . 相反,在这两种情况下,它们都与仍然供电的内存有关,它们都是易失性的记忆 . 去维基百科看看这些 . 静态使用四个晶体管,比如在经典的触发器实现中有两个带反馈的门,你把这个位写入高或低,只要电源没有关闭它就保持它不会忘记的值(只要电源保持打开) . 虽然DRAM使用一个晶体管并且在某种程度上严重依赖于晶体管中的电容,有点像跛脚的可充电电池,你想要它记住1你需要充电它并且它快速放电(以毫秒为单位)所以你必须经常提醒它是一个或零(刷新) .

    所以静态ram是静态的,我们只需要告诉它一次它就会记住,动态ram是动态的,因为我们告诉dram系统那个位是什么,作为一个系统,我们必须不断提醒它,这是通过读取该位然后以特定频率重新编程/充电该位来完成 .

    DRAM很便宜,可以将相同数量的晶体管的数量打包四倍,SRAM很快就没有复杂的开销,也没有刷新周期阻碍,它只是门,因此可以像其他门一样快速运行大门做其他事情(处理指令) .

    微控制器将在其中具有某种形式的非易失性存储器,其中包括ROM,PROM,EEPROM或闪存(其中现在有各种风格) . 有时你可以在这里看到你可能会要求的东西的闪存和eeprom,有时出于反向兼容性的原因,他们有一个eeprom传统接口,但它确实使用主闪存存储 . 无论如何,您必须查看芯片和/或芯片系列的文档 . 目前,应用程序能够写入片上非易失性存储器(eeprom / flash)是很常见的(尽管有很多例外) . 文档告诉您如何执行此操作 .

    这一切都很棒,但是一些免费的建议是,如果你做错了,你可以在几小时或几天内磨损你的闪光灯...字面意思......这个部分可以被摧毁 . 理想情况下,您希望电路板上的支持能够检测到电源下降,同时具有足够的大容量电容或电池或两者,以使电路板/设备保持足够长的时间,以便在最坏的情况下保存非需要的时间 . 易变信息(理想情况下)首先确认值已经改变否则不会烧掉擦除周期) . 实施起来相当简单,但仍然比磨损闪光灯要好 .

    关于如何不磨损闪存的大量解决方案和意见,遗憾的是一些闪存硬件具有写入均衡的逻辑,如果软件和硬件都试图将内容分散以减少闪存的磨损,那么它们可以工作互相攻击,弊大于利 .

    您的器件支持的写入周期数应记录在数据表中,超过使用此器件构建的产品的生命周期,它可能会忘记您编写的内容 . 这是它可能说10000次写入的最低支持,但在测试中,您可能会达到100,000并且有一个仍然有效的设备 . 并不意味着它们的所有重置都将超过数据表中的评级,因此您可以从中反向工作,如果我每隔这么多单位获得一个新值,并且产品的生命周期是我希望这么多单位的时间,然后我不能保存超过一些简单的数学时间单位(每个存储位置/擦除边界等) .

    所以首先要了解如何在应用程序中擦除你没有使用的块,然后给它写一些东西,然后在你重新上电时查看它是否存在,如果没有闪存,请尝试使用eeprom . 这些STM32设备通常记录良好且非常容易 . 然后,一旦你知道如何做到这一点,然后开始担心你觉得你需要做多少次 .

    有些汽车曾经注意到,当你把它们“关闭”并且时钟上的时钟仍然有效时,收音机会记住你最喜欢的电台,或者空气状况会记住你使用的最后温度和风扇速度 . 但如果断开电池,部分或全部电池将丢失 . 他们没有使用非易失性存储,他们正在使用RAM(SRAM),电源只是熄火,他们依赖备用电池 . 主板确实可能仍然为您的“CMOS”或“BIOS”设置执行此操作 . 电池支持ram基本上是因为ram没有断电,主电源可能会关闭,但电池正在保持ram供电 . 这是你可以使用的另一种设计解决方案,一个电池或超级电容(acitor),可能假设你永远不需要存储到闪存,如果像汽车音响,电池就好了 .

    所有这一切都需要我之前的答案,为了进入控制eeprom / flash的寄存器,你需要知道如何从你的程序访问它们:

    这里不需要首先进行位绑定(将一些值存储到/从ram加载),您是否询问如何在ram中写入和读取特定地址,或者您是否在询问如何使用位带?通常你不会使用带有ram的位带,例如,该功能可以改变寄存器中位的子集,设计者由于某种原因将单独的项打包到同一个寄存器中(gpio引脚配置之类的东西是有意义的,而你可能想要在没有软件读取 - 修改 - 写入的情况下更改单个引脚的配置(硬件可能仍需要执行读取 - 修改 - 写入))

    当然你可以在ram上使用bitbanding功能,如果cortex-m允许它我需要重新读取它,不一定有意义,除非你是那个紧紧挨着ram你需要将单独的东西打包成一个单词(比如bitfields,但甚至不开始)...

    #define BITBAND_SRAM_REF   0x20000000
    #define BITBAND_SRAM_BASE  0x22000000
    #define BITBAND_SRAM(a,b)  ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4)))
    #define BITBAND_PERI_REF   0x40000000
    #define BITBAND_PERI_BASE  0x42000000
    #define BITBAND_PERI(a,b)  ((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32  + (b*4)))
    #define MAILBOX            0x20004000
    #define TIMER              0x40004000
    #define MBX_B0             *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0)))
    #define MBX_B7             *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,7)))
    #define TIMER_B0           *((volatile unsigned char*)(BITBAND_PERI(TIMER,0)))
    #define TIMER_B7           *((volatile unsigned char*)(BITBAND_PERI(TIMER,7)))
    
    
    MBX_B0 = 1;
    

    所以这些都不是特别的,或者与皮质或手臂相关,只是基本的C代码 . MBX_B0是一个向后处理宏的宏

    #define MBX_B0             *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0)))
    

    然后

    #define MAILBOX            0x20004000
    #define BITBAND_SRAM(a,b)  ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4)))
    #define BITBAND_SRAM_BASE  0x22000000
    #define BITBAND_SRAM_REF   0x20000000
    

    所以

    0x22000000+(0x20004000-0x20000000)*32 + (0*4)
    
    = 0x22080000
    

    volatile unsigned int只是一种C语法,可以像0x22080009那样取一些常量,并说这是我要指向的地址

    MBX_B0 = 1;
    

    写入0x00000001到地址0x22080000,但由于这是使用位带,这意味着设置地址0x20004000的位0的位1(位带非常特定于这些臂皮质m内核)

    如果你只想将值5写入内存中的某个位置,那么你可以拥有它

    #define SOME_ADD *((volatile unsigned int*)(0x20001234)
    unsigned int x;
    SOME_ADD = 5;
    x = SOME_ADD;
    

    并且看到这一切都为你完成,你可以试试:

    #define BITBAND_SRAM_REF   0x20000000
    #define BITBAND_SRAM_BASE  0x22000000
    #define BITBAND_SRAM(a,b)  ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4)))
    #define MAILBOX            0x20004000
    #define MBX_B0             *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0)))
    
    #define SOME_ADD *((volatile unsigned int*)(0x20001234))
    
    unsigned int fun ( void )
    {
        unsigned int x;
    
        MBX_B0 = 1;
    
        SOME_ADD = 5;
        x = SOME_ADD;
    
    }
    

    arm-none-eabi-gcc -c -O2 so.c -o so.o arm-none-eabi-objdump -D so.o

    00000000 <fun>:
       0:   e3a0c001    mov r12, #1
       4:   e3a02005    mov r2, #5
       8:   e59f1010    ldr r1, [pc, #16]   ; 20 <fun+0x20>
       c:   e59f3010    ldr r3, [pc, #16]   ; 24 <fun+0x24>
      10:   e581c000    str r12, [r1]
      14:   e5832234    str r2, [r3, #564]  ; 0x234
      18:   e5933234    ldr r3, [r3, #564]  ; 0x234
      1c:   e12fff1e    bx  lr
      20:   22080000    andcs   r0, r8, #0
      24:   20001000    andcs   r1, r0, r0
    

    处理器加载地址0x20001000,在这种情况下,汇编器选择将立即0x234添加到该地址而不是将整个0x20001234添加到加载的地址中,六个一个......无论如何都没有不同的成本,因为编写的编译器不需要对齐加载的值 .

    现在,如果您不需要访问特定地址(0x20001234或一些外设寄存器等)然后简单

    unsigned int some_value;
    void fun ( void )
    {
        some_value = 5;
    }
    

    需要编译并链接它以查看整个故事:

    00000004 <fun>:
       4:   e3a02005    mov r2, #5
       8:   e59f3004    ldr r3, [pc, #4]    ; 14 <fun+0x10>
       c:   e5832000    str r2, [r3]
      10:   e12fff1e    bx  lr
      14:   20000000    andcs   r0, r0, r0
    
    Disassembly of section .bss:
    
    20000000 <some_value>:
    20000000:   00000000    andeq   r0, r0, r0
    

    现在代码已经将数字5存储到ram中的某个位置(由链接器选择) .

    在比特带方面,如果你阅读你的手臂文档,你会发现它并不总是受支持,在某些内核中它是一个可选功能,这意味着当他们编译芯片时,他们可以选择不包括它 . 如果对于examaple这是一个特定的st芯片或系列,你可能会发现他们忘记记录一个或两个位带地址(0x22000000,0x42000000)但是它在库中 .

    Personaly我不是挥发性指针技巧的粉丝,我看到编译器无法生成正确的指令,所以我写了一个很小的两行汇编函数,我可以抽象所有这样的访问,通过它强制抽象像无论如何,你将拥有一个Linux或其他驱动程序 . 允许代码更有用,可以抽象访问软件模拟,可以抽象访问逻辑模拟,可以通过mmap抽象,可以在内核驱动程序中使用,可以添加printf层进行调试,单一如果您喜欢这种类型的调试,可以设置一个断点,可以使用几行asm实现裸机,或者如果您愿意,可以使用通用宏/定义来执行易失性指针 . 因人而异 .

    注意局部变量

    void fun ( void )
    {
        unsigned int some_value;
        some_value = 5;
    }
    

    不一定最终在ram中,它们理想地进入堆栈,但如果你进行优化可以优化(推荐用于像微控制器这样资源不足的设备,除非MISRA或其他一些要求阻止你使用优化器) . 上面的代码当然是完全死的代码,结果简单回归:

    00000000 <fun>:
       0:   e12fff1e    bx  lr
    
  • 0

    在阅读bitbanding时,我发现这个代码在Application Note

    我将其复制并编译 . 这应该让你开始 .

    #define BITBAND_SRAM_REF   0x20000000
    #define BITBAND_SRAM_BASE  0x22000000
    #define BITBAND_SRAM(a,b)  ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) // Convert SRAM address
    #define BITBAND_PERI_REF   0x40000000
    #define BITBAND_PERI_BASE  0x42000000
    #define BITBAND_PERI(a,b)  ((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32  + (b*4))) // Convert PERI address
    #define MAILBOX            0x20004000
    #define TIMER              0x40004000 // Mailbox bit 0
    #define MBX_B0             *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0))) // Mailbox bit 7
    #define MBX_B7             *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,7))) // Timer bit 0
    #define TIMER_B0           *((volatile unsigned char*)(BITBAND_PERI(TIMER,0)))  // Timer bit 7
    #define TIMER_B7           *((volatile unsigned char*)(BITBAND_PERI(TIMER,7)))
    
    int main(void)
    {
        unsigned int temp = 0;
    
        MBX_B0 = 1;      // Word write    
        temp = MBX_B7;   // Word read    
        TIMER_B0 = temp; // Byte write    
        return TIMER_B7; // Byte read
    }
    

    有人可以向我解释如何存储例如SRAM中的数字5并再次读取它吗?

    在上面的示例代码中, temp 在RAM中 .

    如果你现在不关心使用bitbanding,只需声明一个变量 int x = 5 将数字5存储在RAM中 .

相关问题