2017-06-06 36 views
-1

我想在芯片的SRAM中存储一个简单的整数。 (Cortex M4) 我使用的程序是mbed在线。 我知道SRAM的地址从0x2000开始,芯片有4KB的内存。如何在STm32核子板(mbed)上写入SRAM

我已阅读数据表和位带部分,但它对我来说没有意义。

有人可以请我解释一下,我可以如何在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);

它只是停止Ç== 100 值应该被保存后也POWER DOWN运行一次。

+1

如果您还没有准备好,请阅读本:[mbed内存型号(https://developer.mbed.org/handbook /内存模型)。 –

+1

在0x20000000处没有带有Cortex-M4内核和4K SRAM的STM32型号。你在使用什么控制器? – berendi

回答

2

编辑,你的问题完全改变了答案,因为你不感兴趣的SRAM写在所有,但闪存/ EEPROM ...

因此增加的主要部分,这个答案,您的评论是非常关键的位置:

但是,即使断电后,该值是否存储?难道SRAM 会代替普通RAM吗? RAM =没电时丢失数值, SRAM =没有电时保持数值?

SRAM表示静态RAM,RAM表示随机存取存储器。现在,随着随机部分与寻址有关,RAM根据该定义可以安全地用于诸如ROM(只读存储器)之类的东西,我可以寻址我想要的任何随机地址还是只能使用线性地址之后读取这个东西其他每个规则。

约定是ROM是非易失性的,而RAM是易失性的,这里是相关的术语。 ROM实现在技术上不是只读的PROM是可编程的ROM,这意味着可写,所以有点可分解术语EPROM电可编程,EEPROM是电可擦除和可编程的。闪存是一种新型的电可擦除可编程ROM或非易失性存储器。

这种意义上的挥发性意味着它可以或不能在电力循环中存活。挥发性意味着它不能以非挥发性手段。

SRAM中的S用于静态确定,这个术语意味着它可能存活尤其是当你学习DRAM时,D意味着动态,并且假设一个在电源周期中存活而另一个不存在但遗憾的是不是他们所指的是什么。相反,在这两种情况下,他们必须处理仍然通电的内存,它们都是易失性存储器。去看看这些在维基百科。静态使用四个晶体管可以说,在经典的触发器实现中有两个反馈门,您可以将该位写入高电平或低电平,只要电源没有关闭,它就保持它不会忘记的值(只要电源保持开启) 。 DRAM虽然使用了一个晶体管,并且在很大程度上依赖于该晶体管中的电容,有点像跛足的可充电电池,但您希望它记住1,您必须对其充电并快速放电(以毫秒为单位),所以您必须不断提醒它是一个还是一个零(刷新)。

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

DRAM价格便宜,可以在相同数量的晶体管中封装四倍的位数,SRAM很快没有复杂的开销,也没有刷新周期,它只是门,所以可以像其他的一样快速运行门的速度与门做其他事情一样快(处理指令)。一个微控制器在其ROM,PROM,EEPROM或闪存(其中现在有各种风味)中将具有某种形式的非易失性存储器。有时候你可能会在eeprom中使用闪存和eeprom,这可能是因为你需要在这里提供的东西,有时为了反向兼容的原因,他们有一个eeprom传统接口,但它确实使用主闪存进行存储。无论如何,您必须查看芯片和/或芯片系列的文档。现在,在应用程序写入片上非易失性存储器(eeprom/flash)时,这很常见(尽管有很多例外)。文档告诉你如何做到这一点。

而且这一切都很棒,但一些免费的建议是,如果你在几小时或几天内做错了这件事,你可以把你的闪光灯磨损掉......这部分可以被删除。理想情况下,您希望在您的电路板上支持检测电源电压下降,同时有足够的大容量电容或电池或两者来保持电路板/设备足够长的时间,以便在需要最短时间的情况下保存电路板/不稳定的信息(理想情况下首先确认数值已经改变,否则不要刻录擦除周期)。很容易实现,但仍然比闪光灯更好。

很多解决方案和意见,关于如何不会损耗你的闪光灯,可悲的是一些闪存硬件有逻辑,写的水平,如果软件和硬件都试图分散东西,以减少磨损闪光他们可以相互抵制,做更多的伤害,而不是好的。

您的零件支持的写入周期数量应记录在数据表中,超过您使用此设备生成的产品的使用期限,它可能会忘记您写的内容。这可能是10000次写入所支持的最小值,但在测试中,您可能会达到10万次,并且仍然可以运行一个设备。并不意味着他们的所有重置都将超过数据表中的评级,所以如果我在这么多单位的时间内获得新的价值并且产品的生命周期是我希望能够达到如此多的单位时间,那么我不能保存超过一些简单的数学时间单位(每个存储位置/擦除边界等)。

所以,首先要学习如何在应用程序中擦除未使用的块,然后向其中写入内容,然后在恢复电源时查看它是否存在,如果不存在则尝试使用eeprom。一般都有文档记录,而且在这些STM32器件上很容易完成。那么一旦你知道如何去做,那就开始担心你觉得你需要这么做了。

有些汽车曾经注意到,当你把它们“关闭”,重新开始时钟仍然有效,收音机会记住你最喜欢的电台或空调记得你使用的最后一个温度和风扇速度。但如果您断开电池的部分或全部电量,则会丢失。他们没有使用使用RAM(非易失性存储器)的非易失性存储器,而且电源刚刚熄灭,它们依靠电池备份。主板已经做好了,也许还会为你的“CMOS”或“BIOS”设置做这些。电池支持的内存基本上是因为内存不会失去电源,主电源可能会关闭,但电池仍然保持内存供电。这是另一个可以使用的设计解决方案,电池或超级电容(acitor),可能会认为您从不需要存储闪光灯,如果像汽车音响那样,电池会很好地熄灭。

授予所有这一切都需要我以前的答案,为了得到那个控制EEPROM /闪存你需要知道如何从程序访问这些寄存器:

首先位绑扎不要求在这里(为了从ram中存储/加载一些值),你是问如何写入和读取RAM中的特定地址,或者你在问如何使用位带?通常情况下,你不会使用ram的位段功能,例如,该功能可以改变寄存器中的一个位子集,设计者因为某种原因将单独的项目打包到同一个寄存器中(像gpio引脚配置这样的事情是有意义的,而你可能需要改变单个引脚的配置,而不用软件中的读 - 修改 - 写入(硬件可能仍然需要进行读 - 修改 - 写))

当然你可以使用ram上的bitbanding功能, cortex-m允许我需要重新读取它,除非你需要将单独的东西打包成单个单词(比如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; 

所以这些都不是特别的,或者与cortex-m或arm相关,只是基本的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 

挥发性unsigned int的东西只是一个C语法的方式,采取像0x22080009一些常数,说这是我想指向的东西的地址

MBX_B0 = 1; 

装置写一个00000001解决0x22080000但是,因为这是使用位条带,这意味着设定地址0x20004000的位0的位1(位绑扎是非常特定于这些臂皮质 - 间核)

如果只是想写值5在内存的某个位置,你可能只是

#define SOME_ADD *((volatile unsigned int*)(0x200) 
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*)(0x200)) 

unsigned int fun (void) 
{ 
    unsigned int x; 

    MBX_B0 = 1; 

    SOME_ADD = 5; 
    x = SOME_ADD; 

} 

臂无 - EABI - 海合会-c -O2 so.c -o so.o arm-none-eabi-objdump -D等等。Ø

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添加到,而不是把整个0x200在加载的地址,一个六...没有不同的成本要么方式,正如编写的编译器不需要对齐加载的值。

现在,如果你是不是需要打一个特定的地址(0x200或一些外设寄存器等),然后简单地

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中的某个位置(由链接器选择)。

如果你阅读arm文档,你会发现它并不总是被支持,在某些内核中它是一个可选功能,这意味着当他们编译芯片时,他们可以选择不包含它。如果说实际上这是一个特定的芯片或家庭,你可能会发现他们忘记记录一个或两个比特带地址(0x22000000,0x42000000),但将其存储在库中。我看过编译器不能产生正确的指令,所以我写了一个很小的两行汇编函数,我可以抽象所有这样的访问,通过它有一个很好的副作用无论如何,强制像你在linux或其他驱动程序中的抽象。允许代码更加有用,可以将访问抽象为软件模拟,可以将访问抽象为逻辑模拟,可以通过mmap进行抽象,可以在内核驱动程序中使用,可以添加用于调试的printf图层,单个如果你喜欢这种类型的调试,可以设置一个断点,可以使用两行asm作为裸机来实现,或者如果你愿意的话,可以使用一个通用的宏/定义来做易失性指针。因人而异。

注意局部变量

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

不一定在RAM结束后,他们最好进入堆叠,但如果你优化(推荐在资源匮乏设备,如微控制器,除非MISRA可以得到优化掉或一些其他的要求阻止你使用优化器)。当然,上面的代码是完全死代码,导致一个简单的回报:

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

你也可以创建一个数组,如果你想编译时间分配(不做运行时分配,这是一个单元没有任何理由让你拥有所有内存,只是使用它)应用程序使用一定数量的RAM,如果由于某种原因该块必须对齐(不知道为什么这些设备),那么只需使用固定地址就像易失性指针一样,作为负责任的程序员和软件工程师,通过做适当的设计避免因为其他原因而使用内存。 –

+0

但是,即使在断电后,该值是否仍然存储? SRAM不是用来代替普通RAM吗? RAM =无电时丢失数值,SRAM =无电时保留数值? –

+0

@AlexM。不,SRAM在断电时仍会丢失数据。只要电源供电,SRAM就会将数据保存在其存储器中,与定期更新的DRAM不同。如果您希望跨电源周期保留值,则需要使用非易失性存储器,如Flash或EEPROM。 –

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中。

+0

谢谢,但有人认为我不明白我究竟该如何存储该号码,我是否将其声明在您的代码下?我要更改'temp'吗?还有一件事是我怎么读取变量后,我更新了我的问题,你可能会再看看它 –