Все ли RAM-разделы используются в этом компоновщике микроконтроллера STM32H743 (Cortex-M7)?

Я знаю, что RAM-память в последних микроконтроллерах STM32 содержит несколько разделов с заметными перепадами скоростей. Вот почему я пытаюсь разобраться в линкерных скриптах для этих устройств (примечание: набор инструментов arm-none-eabi-gcc). К сожалению, скрипт компоновки, сгенерированный CubeMX для STM32F767ZI, просто игнорирует различные разделы в ОЗУ:

/* Specify the memory areas */
MEMORY
{
  RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 512K
  FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 2048K
}


Компания STMicroelectronics, похоже, приложила некоторые усилия, чтобы сделать скрипт компоновки для своего новейшего STM32H743ZI немного более сложным:

/* Specify the memory areas */
MEMORY
{
  DTCMRAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
  RAM_D1 (xrw)      : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)      : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)      : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (xrw)      : ORIGIN = 0x00000000, LENGTH = 64K
  FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 2048K
}

Однако, когда я смотрю дальше в линкерскрипт, кажется, что они запихивают все в DTCMRAM! Все остальные разделы не используются...

Это полный линкерскрипт:

/*
*****************************************************************************
**

**  File        : LinkerScript.ld
**
**  Abstract    : Linker script for STM32H743ZITx Device with
**                2048KByte FLASH, 1056KByte RAM
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used.
**
**  Target      : STMicroelectronics STM32
**
**
**  Distribution: The file is distributed as is, without any warranty
**                of any kind.
**
*****************************************************************************
** @attention
**
** <h2><center>&copy; COPYRIGHT(c) 2014 Ac6</center></h2>
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**   1. Redistributions of source code must retain the above copyright notice,
**      this list of conditions and the following disclaimer.
**   2. Redistributions in binary form must reproduce the above copyright notice,
**      this list of conditions and the following disclaimer in the documentation
**      and/or other materials provided with the distribution.
**   3. Neither the name of Ac6 nor the names of its contributors
**      may be used to endorse or promote products derived from this software
**      without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20020000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
DTCMRAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw)      : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw)      : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw)      : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw)      : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 2048K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >DTCMRAM AT> FLASH


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >DTCMRAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >DTCMRAM



  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

Значит ли это, что все остальные разделы в оперативной памяти остаются неиспользованными? Зачем им это делать?


Если вы можете улучшить этот скрипт компоновки (и сделать другие разделы оперативной памяти полезными), скопируйте и вставьте свое улучшение в свой ответ. Я был бы очень признателен. Пожалуйста, также укажите, как на самом деле можно определить в исходном коде C (или исходном коде C++), где определенные данные попадают в ОЗУ. Для меня это до сих пор загадка ^_^


person K.Mulier    schedule 13.07.2018    source источник
comment
что происходит, когда вы добавляете в свой проект какие-то .bss или .data, может быть это фальшивые глобальные вещи, которые подталкивают вас к 128K? Я бы предположил, что с xrw он будет перетекать в следующий раздел.   -  person old_timer    schedule 13.07.2018


Ответы (1)


С помощью gcc вы можете добавить к переменным атрибут раздела. На основании этого переменная затем перемещается в конкретный сеанс.

Например. Допустим, у вас есть большой массив:

#define BUF_SIZE 2048

__attribute__ ((section(".buffers"), used))
uint8_t pipe_buffer[BUF_SIZE];

Затем вы добавляете раздел в скрипт загрузчика и назначаете его определенной области памяти (в данном случае RAM_D3):

.buffers(NOLOAD) : {
    . = ALIGN(4);
    *(.buffers*)
} > RAM_D3

Таким образом, буферы оказываются в RAM_D3.

person Codo    schedule 13.07.2018
comment
Спасибо @Кодо! Что такое NOLOAD, который вы поместили в линкерскрипт? Является ли это признаком того, что этот раздел похож на раздел bss: не инициализирован? Если это так, то почему раздел bss начинается так: .bss : {...} вместо .bss(NOLOAD) : {...}? - person K.Mulier; 13.07.2018
comment
Кроме того, означает ли это, что STMicro ожидает, что пользователь добавит такой код в скрипт компоновки, иначе все эти другие разделы RAM будут недоступны? - person K.Mulier; 13.07.2018
comment
Скорее всего (NOLOAD) не нужен. Загрузка относится к процессу загрузки исполняемого файла, находящегося на диске, в память. Для MCU исполняемый файл находится во FLASH. Поэтому ни один из разделов не может быть загружен. - person Codo; 13.07.2018
comment
У вас есть несколько вариантов использования специальных разделов оперативной памяти. 1. С помощью скрипта компоновщика, как описано выше. 2. Если предусмотрена специальная версия malloc, принимающая дополнительный параметр для выбора раздела оперативной памяти (в SDK для ESP32 предусмотрена такая функция) 3. Вы присваиваете значение 0x38000000 указателю. Тогда у вас есть массив в RAM_D3. 4. Некоторые другие, которые вы можете придумать... STMicro, похоже, не предоставляет какой-либо конкретной поддержки. Если я не ошибаюсь, MCU также может использовать внешнюю оперативную память. Это снова изменило бы историю. - person Codo; 13.07.2018
comment
Привет @Codo. Похоже, что STMicro только что поместил эти разделы RAM в линкерскрипт, но не подготовил линкерскрипт к их использованию? - person K.Mulier; 13.07.2018
comment
да. Если нет других вариантов gcc для перемещения чего-либо в определенный раздел, о которых я не знаю. - person Codo; 13.07.2018
comment
Спасибо @Кодо. Ваш ответ был очень полезен. Я дам ему некоторое время (чтобы получить больше информации от других), затем я отмечу ваш ответ :-) - person K.Mulier; 13.07.2018
comment
@K.Mulier это вполне логично. Они по-разному связаны с ядром. Дизайнер должен решить, какой раздел памяти и как его использовать. Это не процессор приложения. Глубокое знание используемого инструмента (компилятора) подразумевает - person 0___________; 13.07.2018
comment
Насколько я знаю, GCC не может распространять вещи автоматически, поэтому вам нужно выбрать регион по умолчанию, куда идет все, что не относится к явно указанному разделу. - person starblue; 14.07.2018
comment
@ K.Mulier, кажется, ты забыл пометить этот ответ как принятый (или дать другую интерпретацию какого-то времени) ;-) - person wovano; 17.11.2020
comment
@ K.Mulier, имеет смысл, что STM предоставил этот скрипт компоновщика, который использует только DTCMRAM. Это самая быстрая и простая оперативная память. Например, вам не нужно заботиться о кэшах. Для более продвинутых вариантов использования, например. если вам нужен полный объем памяти или DMA для передачи данных, вам придется гораздо больше понимать архитектуру и делать некоторые конкретные решения, которые могут сильно повлиять на производительность. Эти варианты должны быть отражены в скрипте компоновщика и могут различаться в зависимости от варианта использования. - person wovano; 17.11.2020