本文已参加「新人创造礼」活动,一同敞开创造之路。

移植micropython的最小工程到lpc5500微控制器(2) – 调整内存分配

调整linker文件

调整linker文件实际上是确定对芯片存储空间的运用组织,特别是对数据区、堆和栈空间的组织。

linker文件仍是运用SDK的原版“LPC55S69_cm33_core0_flash.ld”文件作为模板,但是我考虑要调整其间的内存分块,并且要精简掉不必要的分区,所以单独复制出一份放到“lpc5500”项目的根目录中,便于自己随意改动。

先看一眼lpc55s69芯片的内存资源:

移植micropython的最小工程到lpc5500微控制器(2) - 调整内存分配

移植micropython的最小工程到lpc5500微控制器(2) - 调整内存分配

其间从0x2000_0000开端的惯例SRAM就有256KB,16KB的PowerQUAD专有内存就不去碰了,从0x1400_0000开端的32KB内存我一开端没好意思用,后面考虑把data(和bss)部分和工程自带的堆放进去,然后把256KB的惯例SRAM空间全部预留给栈空间和给micropython的gc内存办理器运用。

这里有个知识点,关于micropython工程的内存运用状况:

  • micropython统辖的内存主要是整个体系的栈空间(用来动态编译的放字节码)和gc办理的私有堆空间(寄存micropython运转过程中创立的对象)。micropython在运转的初始阶段就要通过代码指定其统辖的栈内存区域和私有堆空间。
  • micropython统辖之外的体系层面上运用的数据,例如一些进入micropython之前的硬件初始化函数,体系库函数等运用的数据,一部分放在体系栈空间(micropython会让出这部分栈空间),另一部分放在体系堆空间中(很少)。
  • micropython对接底层驱动时,在编写C代码过程中,例如驱动程序,创立的全局变量将会放在体系的data段(或许bss段)中,局部变量同micropython惯例的函数调用一样,寄存在体系栈中。

依照这个原则,在linker文件中进行调整,我的改动包括如下:

将惯例SRAM分红两块

/* Specify the memory areas */
MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000140
  m_text                (RX)  : ORIGIN = 0x00000140, LENGTH = 0x0009D000
  m_data                (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00020000
  m_data2               (RW)  : ORIGIN = 0x20020000, LENGTH = 0x00020000
  m_usb_sram            (RW)  : ORIGIN = 0x40100000, LENGTH = 0x00004000
}

我将惯例SRAM分红了m_data和m_data2两块,都是128KB巨细。m_data计划用来寄存data(bss)和栈,m_data2整块给GC作为micropython的私有堆空间。

原始版本中的用于多核通信的共享内存区域和预留寄存双核体系中另一个核的text段被合并到现有区块中,因为micropython中暂时用不到,所以就精简掉了,后面对应区块的界说也能够删掉。至于m_text区域为啥没有填满整个640KB的空间,而是只用了大约630KB的空间,也是参阅了手册中关于内存分布状况的说明(见上图),最终这10 KB的空间是预留的,这个或许寄存了一些同芯片硬件配置相关的一些数据,总之不要碰它就好。

增大栈的巨细

HEAP_SIZE  = DEFINED(__heap_size__)  ? __heap_size__  : 0x0400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x1C000; /* 112 KB. */

这里指定了栈空间为112KB,放在m_data中。体系堆保存原来的512字节,在用户程序里肯定用不到,但说不准体系库会偷偷摸摸地用一点,所以多少保存一点,也放在m_data中。

  /* Uninitialized data section */
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    . = ALIGN(4);
    __START_BSS = .;
    __bss_start__ = .;
    *(.bss)
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
    __END_BSS = .;
  } > m_data
  .heap :
  {
    . = ALIGN(8);
    __end__ = .;
    PROVIDE(end = .);
    __HeapBase = .;
    . += HEAP_SIZE;
    __HeapLimit = .;
    __heap_limit = .; /* Add for _sbrk */
  } > m_data
  .stack :
  {
    . = ALIGN(8);
    . += STACK_SIZE;
  } > m_data

增加micropython需要引用的变量

这部分代码是参阅imxrt的相关代码增加的,详细便是“ports/mimxrt/boards/MIMXRT1062.ld”文件中的内容。这些变量从linker过程中导出,然后在micropython初始化过程中指定统辖内存规模时传参运用。

/* 112kiB stack. */
/*__stack_size__ = 0x1C000;*/
_estack = __StackTop;
_sstack = __StackLimit;
/* Use 128KB for GC heap. */
_gc_heap_start = ORIGIN(m_data2);
_gc_heap_end = ORIGIN(m_data2) + LENGTH(m_data2);

这里能够看到,gc统辖的私有堆运用了整个m_data2,而整个体系栈的开端和完毕方位也被记录在_estack和_sstack变量中。

这两组变量在main()函数开端的时候会被运用到:

int main(void)
{
    ...
    mp_stack_set_top(&_estack);
    mp_stack_set_limit(&_estack - &_sstack - 1024);
    gc_init(&_gc_heap_start, &_gc_heap_end);
    ...
}

其间设置micropython栈尾的时候又减去了1K字节的长度,此处猜想应该是避免暂时的栈溢出触发体系溃散的防护措施,把体系栈同别的内存隔远一点更加安全。

(未完待续。。。)