gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 18:28:52 29 4
gpt4 key购买 nike

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

我已经阅读了数据手册和位带化部分,但是对我而言这没有意义。

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

当前代码如下(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,它就停止运行
掉电后也应保存该值。

最佳答案

编辑,您的问题完全改变了答案,因为您根本不对SRAM写入感兴趣,而对Flash / eeprom感兴趣...

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


  但是,即使断电也可以存储该值吗?那不是SRAM吗
  会代替普通的RAM吗? RAM =断电时的损耗值,
  SRAM =无电时保持值?


SRAM表示静态RAM,RAM表示随机存取存储器。现在,根据该定义,RAM可以安全地用于ROM(只读存储器)之类的事情,因为随机部分与寻址有关,我可以寻址我想要的任何随机地址,还是只能在之后使用线性一个地址读取此东西?另一些规则。

约定是ROM是非易失性的,RAM是易失性的,这是此处的相关术语。 ROM的实现不是技术只读的,PROM是可编程的rom,这意味着它是可写的,因此有点破坏了EPROM的电可编程性,EEPROM的电可擦除和可编程性。闪存是一种可擦除和可编程的只读存储器或非易失性存储器的较新技术。

从这个意义上说,挥发性意味着它可以或无法在电源循环中幸存下来。不稳定意味着它不能非易失性意味着它可以。

SRAM中的S表示静态,该术语表示当您学习DRAM时该术语暗示它可能会生存,特别是D表示动态,并且很好地假设一个生存于电源循环中,而另一个则生存,但不幸的是,这并不是它们所指的含义。 。取而代之的是,在两种情况下,它们都与保持供电的内存有关,它们都是易失性存储器。去维基百科上查找这些。静态使用四个晶体管,可以说,在经典触发器实现中有两个具有反馈的门,您将位写为高电平或低电平,并且只要电源不关闭,它就不会忘记它的值(只要电源保持导通)。 。 DRAM虽然使用一个晶体管,但在某种程度上严重依赖于该晶体管中的电容,就像是可充电的la脚电池一样,您希望它记住一个1,您必须对其充电并迅速放电(以毫秒为单位),所以您必须不断提醒它是一或零(刷新)。

所以静态ram是静态的,从某种意义上来说,我们只需要告诉一次它就可以记住;动态ram是动态的,从某种意义上说,我们告诉dram系统该位是什么,而作为一个系统,我们必须不断提醒它,这是通过读取该位然后以一定频率对该位重新编程/充电来完成。

DRAM价格便宜,可以将四倍的位数封装到相同数量的晶体管中,SRAM快速,没有复杂的开销,也没有刷新周期,它只是门,因此可以像其他门一样快地运行大门正在做其他事情(处理指令)。

微控制器将在其ROM,PROM,EEPROM或闪存(现在有多种形式)中具有某种形式的非易失性存储。有时,您可能同时需要Flash和eeprom eeprom,有时出于反向兼容性原因,它们具有eeprom传统界面,但实际上是使用主闪存进行存储。无论如何,您都必须查看芯片和/或芯片系列的文档。如今,在应用程序中能够写入片上非易失性存储器(eeprom /闪存)是很普遍的(尽管有很多例外)。并且文档告诉您如何执行此操作。

很棒,但是有一些免费的建议,如果您在数小时或数天内做错了,您可以用光了闪光灯。理想情况下,您希望主板上的支持能够检测到功率下降,同时具有足够的大容量电容或电池或两者兼有,以使主板/设备的使用寿命足够长,以节省最坏的时间。易失性信息(最好先确认值已更改,否则不要消耗擦除周期)。实施起来很简单,但仍然比用完闪光灯要好。

关于如何不使闪存磨损的解决方案和意见很多,令人遗憾的是,某些闪存硬件具有确实可以进行写平衡的逻辑,如果软件和硬件都在尝试扩展内存以减少闪存的磨损,它们就可以工作互相伤害,弊大于利。

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

因此,首先要学习在应用程序中如何擦除不使用的块,然后向其写入内容,然后在重新上电时查看该块是否存在,如果没有闪存,请尝试eeprom。通常在这些STM32器件上有据可查且非常容易实现。然后,一旦您知道该怎么做,便开始担心需要多久进行一次操作。

曾经注意到在某些汽车中,当您将它们“关闭”并重新打开时,它仍然可以工作,收音机会记住您喜欢的电台,或者空调会记住您使用的最后温度和风扇速度。但是如果您断开电池的连接,部分或全部将丢失。他们没有使用非易失性存储设备,而是在使用ram(SRAM),并且电源完全关闭,他们依靠备用电池。主板可以并且仍然可以针对“ CMOS”或“ BIOS”设置执行此操作。电池支持的ram基本上是因为ram不会断电,主电源可能会熄灭,但是电池一直为ram供电。那是您可以使用的另一种设计解决方案,即电池或超级电容(电池),可能会假设您不需要存放闪光灯,如果像汽车立体声音响那样,电池没电了。

获得所有这些都需要我事先回答,为了获得控制eeprom / flash的寄存器,您需要知道如何从程序中访问它们:

这里不需要首先(也是最重要的)位带化(将某些值存储到ram中/从ram加载一些值),您是在问如何在ram中的特定地址中读写数据,还是在问如何使用位带化?通常,您不会在ram上使用位绑定,例如,该功能可以更改寄存器中的位子集,在某些情况下,设计人员出于某种原因将单独的项目打包到同一寄存器中(例如gpio引脚配置之类的东西很有意义,可能需要更改单个引脚的配置,而无需在软件中进行读-修改-写操作(硬件可能仍必须进行读-修改-写操作))

当然,如果cortex-m允许,您可以在ram上使用位带功能,我需要重新阅读一下,并不一定有意义,除非您对ram感到非常饥饿,需要将单独的内容打包成一个单词(就像位域一样,但是甚至不以它开头)...

#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


volatile unsigned int东西只是采用C语法的方式来获取诸如0x22080009之类的常量,并说这是我要指向的东西的地址

MBX_B0 = 1;


表示将0x00000001写入地址0x22080000,但是由于这是使用位绑定,因此意味着将地址0x20004000的位0的位1置1(位绑定非常特定于这些arm cortex-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中的某个位置(由链接器选择)。

从细节上看,如果您阅读Arm文档,就会发现它并不总是受支持,在某些内核中,它是一项可选功能,这意味着当他们编译芯片时,他们可以选择不包含它。而且,例如,如果这是一个特定的st芯片或系列,则可能会发现他们忘记记录一个或两个位带地址(0x22000000,0x42000000),但是将其存储在库中。

我个人不是挥发性指针技巧的狂热者,我看到编译器无法生成正确的指令,所以我编写了一个很小的两行汇编函数,可以对所有此类访问进行抽象,通过这种方式,强制执行类似无论如何,您将在linux或其他驱动程序中使用。允许代码更加有用,可以抽象化对软件仿真的访问,可以抽象化对逻辑仿真的访问,可以通过mmap抽象,可以在内核驱动程序中使用,可以添加printf层以这种方式进行调试,单个如果您喜欢那种调试类型,可以在此处设置一个断点,可以用几行asm来实现裸机,或者可以使用通用宏/定义来执行volatile指针。 YMMV。

注意局部变量

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


不一定会以ram结尾,它们理想情况下会放在堆栈上,但是如果您进行优化,则可以将其优化(建议使用像微控制器这样的资源匮乏的设备,除非MISRA或其他要求阻止您使用优化器)。上面的代码当然是完全死代码,导致简单的返回:

00000000 <fun>:
0: e12fff1e bx lr

关于c - 如何在STm32核板上写入SRAM(mbed),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44399487/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com