Распределение памяти во встроенных системах - PullRequest
0 голосов
/ 25 декабря 2018

Системы Linux / Unix часто работают на архитектуре процессора x86, которая обеспечивает MMU для отображения памяти, но я полагаю, что во встроенных системах этого нет, поэтому malloc и free.

Я видел, что программисты ESможет создать большой статический буфер для резервирования памяти:

unsigned char mem[10240];

Но мне интересно, как он работает, где именно запускается буфер и как компилятор C может отображать определения переменных в фактические ячейки памяти на некоторых платформах.

Я также видел такие константы в заголовках ES (извлеченные из ARM STM32L1xx):

#define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */

Я понимаю, что SRAM означает "статическая" RAM, но имеет "базовый адрес"означает начало области памяти, зарезервированной для доступа к куче / стеку, чтобы программист мог выделить и освободить куски ОЗУ, используя указатель на этот базовый адрес и связанный список блоков?

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

Embedded System - это очень широкий термин.Это может означать микроконтроллер без операционной системы или «обычный» компьютер с ОС.

Некоторые примеры:

  • uC читает датчики и контролирует поток воды через трубу.
  • Raspberry Pi работает под управлением Linux, управляя дроном (он встроен вДрон)
  • ПК-компьютер, управляющий лазерным резаком.
  • мэйнфрейм-компьютер в системе радиотелескопа

Так что нет единого ответа на ваш вопрос.

ОК будут программироваться совершенно иначе, чем RPi, используемые в дроне.

Но ваш вопрос, вероятно, касается систем uC, я думаю.

Системы uC обычно программируют, иногда их называют «голым железом», потому что у программистов нет непосредственного программного обеспечения (уровня абстракции) междуих применение и фактическое оборудование.Таким образом, они получают доступ к памяти, аппаратным регистрам и другим ресурсам напрямую.Даже операционные системы, используемые в разработке с нуля (называемые ОСРВ), даже не похожи на обычные ОС, такие как Linux или Windows.Это больше библиотек, связанных вместе с приложением «голое железо», и они просто обеспечивают механизмы управления задачами и связи, синхронизации и обмена данными.

Некоторые вопросы, которые вы задали в комментариях

DMA - Прямой доступ к памяти- позволяет передавать данные между памятью и периферийными устройствами или памятью без использования ядра процессора.Некоторые системы управления доступом имеют очень сложные DMA и системы событий - например, переполнение таймера может вызвать АЦП, который запускает передачу DMA, сохраняя преобразованные данные в памяти.

Сценарий компоновщика - определяет, что, как и где хранится впамять.Они могут быть очень сложными и проинструктировать, какой код или данные включить или исключить, и как организовать память программы.Ниже приведен пример сценария компоновщика для семейства MMC STM32 uC

/* Entry Point */
ENTRY(Reset_Handler)

_estack = 0x10004000;    /* end of RAM */

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x100;      /* required amount of heap  */
_Min_Stack_Size = 0x1000; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 64K
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 16K
FLASH (rx)      : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 34K
}

_FLASH_SIZE = LENGTH(FLASH);

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

  .sizedata :
  {
    . = ALIGN(4);
    KEEP(*(.sizedata))
    KEEP(*(.sizedata*)) 
    . = ALIGN(4);
  } >FLASH  

    .flashdata :
  {
    . = ALIGN(4);
    KEEP(*(.rodata))         /* .rodata sections (constants, strings, etc.) */
    KEEP(*(.rodata*))       /* .rodata* sections (constants, strings, etc.) */
    . = 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);
   _ROMEND = .;


  /* Initialized data sections goes into CCMRAM, 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 */
  } >CCMRAM AT> FLASH

   _ROMSIZE = _ROMEND - ORIGIN(FLASH) + _edata - _sdata;

  _siccmram = ORIGIN(CCMRAM);
    _sconfig = _ROMSIZE;
  _econfig = _sconfig + 2K;
    .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;
  } >CCMRAM

  /* RAM section 
  */

      /* Uninitialized data section */
   .dummy :
   {
   . = ALIGN(4);
   *(.dummy)
   *(.dummy*)
   . = ALIGN(4);
   } > RAM AT > FLASH

  .ram :
  {  
    . = ALIGN(4);
    _sram = .;       /* create a global symbol at ccmram start */
    *(.ram)
    *(.ram*)   
    . = ALIGN(4);
    _eram = .;       /* create a global symbol at ccmram end */
  } >RAM 

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



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


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

- некоторые контроллеры имеют блоки управления памятью, но обычно это периферийное устройство защищает только некоторые области памяти.Поскольку у вас нет ОС, у вас также нет файловой системы - поэтому нет ничего похожего на mmap.

  #define SRAM_BASE ((uint32_t)0x20000000)

он только определяет в удобочитаемой форме человека адрес чего-либо.В этом случае, вероятно, это просто адрес начала памяти SRAM.Другой пример:

#define PERIPH_BASE           ((uint32_t)0x40000000U)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x00010000U)
#define SPI1_BASE             (APB2PERIPH_BASE + 0x00003000U)
#define SPI1                ((SPI_TypeDef *) SPI1_BASE)
0 голосов
/ 25 декабря 2018

У меня сложилось впечатление, что есть некоторые недоразумения, связанные с этим вопросом.Позвольте мне попытаться разобраться в них.

Функция malloc и free не требует MMU.
Тот факт, что вы видели одну реализацию, использующую MMU, не означает, что она всегда нужна.
Хотя MMU может упростить реализацию, а в случае PMMU даже отложить сбой попыток malloc (используя виртуальную память), реализация этих двух функций для статически распределенных переменных возможна.Использование подходящих больших массивов (как вы упоминаете) - способ сделать это.Я сделал это по крайней мере в двух разных случаях, чтобы приспособиться к реализации приложений, которые используют динамическое распределение памяти.
Обратите внимание, что во встроенных системах необходимы расширенные знания о поведении системы, чтобы использовать соответствующие алгоритмы и размер, чтобы избежать истощенияпамяти (как правило, вызвано или усугубляется фракцией).Но для встроенной системы это знание иногда доступно.

Использование такого массива означает, что он сначала выделяется компоновщиком совершенно нормально, как и любая другая (большая) переменная.
Адрес для этого определяетсякомпоновщик, в зависимости от конфигурации и системных атрибутов.Одно вероятное местоположение находится внутри сегмента BSS (глобальные или статические переменные без инициализации определенного значения).

Последний абзац вашего вопроса особенно неясен и, кажется, переключается между несколькими темами.
Да, SRAM предназначен длястатическая RAM.«Статическое» в этом, однако, не связано ни с одним из значений в соответствии с синтаксисом Си.«Статический» SRAM относится к аппаратной реализации памяти.Это в отличие от динамического ОЗУ.Динамическая ОЗУ намного дешевле, чем статическая, однако требует регулярного обновления.Обновление практически всегда выполняется MMU, но я не вижу никакой связи с другим случаем MMU, о котором вы упомянули.SRAM может хранить свой контент только с помощью источника питания, DRAM теряет контент через довольно короткое время.Для этого SRAM может использоваться во встроенных системах для хранения контента между фазами, в которых ЦП практически не работает, что часто называют «режимами пониженного энергопотребления».

Термин «базовый адрес» имеет много значений.Это может относиться, например, к наименьшему адресу области, используемой для распределения переменных BSS, или к наименьшему адресу области, используемой для динамического управления памятью.

Программатор распределяет память динамически, НЕ передавая указатель, это сделановместо этого запрашивая указатель, который является возвращаемым значением, например, успешной попытки malloc.

Реализация выделяет динамическую память внутри области памяти, доступной специально для этой цели (которая может быть упомянутым большим массивом).Если память доступна (например, все еще найдены блоки в связанном списке свободных блоков), он возвращает адрес внутри одного из них (за которым, конечно, следует достаточно свободного места для размещения запрошенного размера), и сохраняет информацию об оставшихся(если есть) свободная память (например, путем вставки этого теперь меньшего пространства обратно в связанный список).Если памяти больше не осталось, возвращаемое значение указывает на ошибку.

...