Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Динамическое выделение памяти в SDRAM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Atlantis-
Здравствуйте!
Можно ли динамически с помощью функции malloc() выделять память во внешней памяти SDRAM?
Golikov A.
можно если договоритесь с линкером там разместить кучу...
Atlantis-
Цитата(Golikov A. @ Nov 19 2014, 16:03) *
можно если договоритесь с линкером там разместить кучу...

можно поподробней, у меня проект в Keil, надо видимо как то опции проекта настроить
Golikov A.
вот выписка из их хелпа

Цитата
Creating the heap for use with microlib
ARM Compiler toolchain v5.02 for µVision Using ARM C and C++ Libraries and Floating-Point Support

Home > The ARM C micro-library > Creating the heap for use with microlib

Creating the heap for use with microlib
To use the heap functions, for example, malloc(), calloc(), realloc() and free(), you must specify the location and size of the heap region.

To specify the start and end of the heap you can use either of the following methods:

use a scatter file

define symbols __heap_base and __heap_limit.

The scatter file method uses ARM_LIB_HEAP and ARM_LIB_STACKHEAP.

Otherwise, specify the start and end of the heap by defining symbols __heap_base and __heap_limit respectively. On completion, you can use the heap functions in the normal way.

Note
The __heap_limit must point to the byte beyond the last byte in the heap region.

Example 17 shows how to set up the heap pointers using assembly language.

Example 17. Assembly language

EXPORT __heap_base
__heap_base EQU 0x400000 ; equal to the start of the heap
EXPORT __heap_limit
__heap_limit EQU 0x800000 ; equal to the end of the heap


Example 18 shows how to set up the heap pointer using embedded assembler in C.

Example 18. Embedded Assembler in C

__asm void dummy_function(void)
{
EXPORT __heap_base
__heap_base EQU 0x400000 ; equal to the start of the heap
EXPORT __heap_limit
__heap_limit EQU 0x800000 ; equal to the end of the heap
}





ну и задать heap в область DRAMа
Atlantis-
то есть startup файл не трогать, а после настройки SDRAM вызвать прямо в программе функцию со своими значениями heap_base и heap_limit?

Код
__asm void dummy_function(void)
{
EXPORT __heap_base
__heap_base EQU 0x400000; equal to the start of the heap
EXPORT __heap_limit
__heap_limit EQU 0x800000; equal to the end of the heap
}



Цитата(Golikov A. @ Nov 19 2014, 18:05) *
ну и задать heap в область DRAMа

что это значит?

а в настройках проекта во вкладке Target надо прописывать Memory Areas ?
Golikov A.
вам надо сделать scater файл
на закладе линкер есть возможность править его руками
и в этом скатер файле указать константы __heap_base, __heap_limit - тем самым определить где у вас находиться куча и ее размер.
функции выделения памяти выделяют ее из кучи. Следовательно разместив кучу в SDRAMе они будут выделять память оттуда...

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

Так что я бы предпочел вариант через скатер файл все разложить до компиляции, ну чтобы наверняка
Atlantis-
Если во вкладке Linker снять галочку Use Memory Layout from Target Dialog, то становится доступен Scatter file. У меня там по умолчанию вот что:
Код
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00200000  {   ; load region size_region
  ER_IROM1 0x08000000 0x00200000  { ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00030000  { ; RW data
   .ANY (+RW +ZI)
  }
}


и мне нужно отредактировать его вот так?
Код
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00200000  {   ; load region size_region

ARM_LIB_HEAP 0xD0000000 EMPTY 0x800000 { };Heap region growing up

  ER_IROM1 0x08000000 0x00200000  { ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00030000  { ; RW data
   .ANY (+RW +ZI)
  }
}

для SDRAM размером 8 мегабайт с адреса 0xD0000000

а параметры кучи расположенные в стартап файле будут проигнорированы?
Golikov A.
насколько я помню в стартап файле параметры кучи задан как раз относительно констант __heap_base и __heap_limit, то есть логичнее в скатер файле определить их, и тогда они в стартапе автоматически подставятся... Правда у меня стартам от LPC, может STM по другому его пишет, и я тогда ввожу вас в заблуждение... но не думаю, ибо это кейловские константы, и они должны были бы их поддержать.

Проверить можно сделав переменную, эмалокнуть ее и поглядеть куда она попала.
Atlantis-
в стартапе вот что
Код
; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB


проверил - malloc возвращает значение меньше 0xD0000000 и при попытке выделить больше заданного в стартапе выдает NULL
Golikov A.
ну то есть не победа.


проверьте {} скобочки в скатере

LR_IROM1 0x08000000 0x00200000 { ; load region size_region

у вас этот регион закрывается в конце, а вроде как должен закрыться до


ARM_LIB_HEAP 0xD0000000 EMPTY 0x800000 { };Heap region growing up

и определите константы __heap_base и __heap_limit


ARM_LIB_HEAP - может вообще быть для своих кейловских целей, для их бибилотечных маалоков...
Atlantis-
Цитата(Golikov A. @ Nov 20 2014, 11:49) *
ну то есть не победа.


проверьте {} скобочки в скатере

LR_IROM1 0x08000000 0x00200000 { ; load region size_region

у вас этот регион закрывается в конце, а вроде как должен закрыться до


ARM_LIB_HEAP 0xD0000000 EMPTY 0x800000 { };Heap region growing up

я расстановку скобок тут смотрел http://www.keil.com/forum/21257/stm32f4-st...g-scatter-file/

Цитата(Golikov A. @ Nov 20 2014, 11:49) *
и определите константы __heap_base и __heap_limit

ARM_LIB_HEAP - может вообще быть для своих кейловских целей, для их бибилотечных маалоков...

где определить? в Scatter?

еще вопрос, как malloc может вернуть адрес больше 0xD0000000 если 0xD0000000 - это unsigned int, a malloc возвращает int?
Golikov A.
в хелпе было написано что в скатере надо определять, попробуйте вместо ARM_LIB_HEAP 0xD0000000 EMPTY 0x800000 { };Heap region growing up

ответ на второй вопрос в том что malloc определен как
void *malloc(size_t size)
а не int

вот кстати ваш вопрос и ответ
http://www.lpcware.com/zh-hans/node/1108143
Atlantis-
Цитата(Golikov A. @ Nov 20 2014, 15:33) *
в хелпе было написано что в скатере надо определять, попробуйте вместо ARM_LIB_HEAP 0xD0000000 EMPTY 0x800000 { };Heap region growing up

если поместить это в скатер, то компилятор ругается
Код
__heap_base EQU 0xD0000000       ; equal to the start of the heap


Цитата(Golikov A. @ Nov 20 2014, 15:33) *
вот кстати ваш вопрос и ответ
http://www.lpcware.com/zh-hans/node/1108143

тут говорят надо функцию прописать
Код
__asm void dummy_function(void)
{
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit

__initial_sp EQU STACK_BASE
__heap_base EQU HEAP_BASE
__heap_limit EQU (HEAP_BASE + HEAP_SIZE)
}

только я не понимаю где ее прописать и когда вызвать
Golikov A.
там написано что можно задать эти переменные в асмовом файле, или через функцию.

Думаю стартап как асмовый файл подойдет


а в скатере скорее всего надо как то по другому писать, хорошо бы где то синтаксис его найти...

попробуйте

#define __heap_base 0xD0000000

вот кстати интересно
http://www.keil.com/support/man/docs/ARMLI...59122863069.htm

как следствие
http://www.keil.com/support/man/docs/armli...62065977713.htm

не означает ли это, что надо еще и функцию вызывать чтобы начать пользоваться смещенной кучей?
Atlantis-
определил в стартапе
Код
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
;my code
__heap_base EQU 0xD0000000
__heap_limit EQU (0xD0000000 + 0x00800000)
;end my code
                
                 ELSE
                
                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap
                
__user_initial_stackheap

при попытке выделить 8 000 000 байт возвращает не NULL, но и возвращаемый адрес меньше 0хD0000000
как вообще правильно посмотреть возвращаемый адрес? у меня если точку остановки поставить после маллок и навести курсор на маллок показывает одно число, а в окне Watch1 другое
после попытки записать в конец памяти улетает в хардфаулт
Код
p[5000000] = 10;

Golikov A.
Код
int *Pointer = 0;
int A = 0;
Pointer =  malloc(10);
A = Pointer;

оптимизацию всю отключить, по умолчанию она в дефолте и это не 0, а -2...

и смотрите это А
Atlantis-
адрес правильный возвращает, но при попытке инициализировать больше 2 050 000 элементов вылетает в хардфаулт
делаю так
Код
    uint32_t *p = NULL;
    uint32_t *p1 = NULL;
    uint32_t Test =0;

        p = malloc(8000000);//выделил 8 000 000 байт

        Test = (uint32_t)p;//адрес получается 0xD0000008

        for (int i=0; i < 2100000; i++)//улетает в хардфаулт, если i<2 050 000 то не улетает
        {
            p[i] = 4;
        }
scifi
Цитата(Atlantis- @ Nov 21 2014, 11:15) *
адрес правильный возвращает, но при попытке инициализировать больше 2 050 000 элементов вылетает в хардфаулт

Что-то я не пойму, выход за границу массива - это так и задумано? Или вы просто не в курсе, что элемент с номером 2050000 - это байт с номером 8200000?
jcxz
Цитата(scifi @ Nov 21 2014, 14:21) *
Что-то я не пойму, выход за границу массива - это так и задумано? Или вы просто не в курсе, что элемент с номером 2050000 - это байт с номером 8200000?

Это просто традиция здесь такая - в качестве дебаггера использовать electronix.ru/forum.
....а иногда и в качестве головы. biggrin.gif
Atlantis-
Цитата(scifi @ Nov 21 2014, 11:21) *
Что-то я не пойму, выход за границу массива - это так и задумано? Или вы просто не в курсе, что элемент с номером 2050000 - это байт с номером 8200000?

не в курсе. теперь разобрался. из-за того что *p у меня uint32_t выделяется по 4 байта а не по одному

по теме - вот что на форуме my.st посоветовали по настройке heap
CODE

// STM32 Keil SDRAM HEAP STM32F429I-DISCO - sourcer32@gmail.com

// Use MicroLIB checked in options
// Use Scatter file in Linker options (not Memory Layout from Target Dialog)

/* heap.sct

LR_IROM1 0x08000000 0x00200000 { ; load region size_region
ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00030000 { ; Internal SRAM
.ANY (+RW +ZI)
}
RW_IRAM2 0x10000000 UNINIT 0x00010000 { ; Internal CCM SRAM
*(.ccm)
}
RW_RAM1 0xD0000000 UNINIT 0x00800000 { ; External SDRAM
*(HEAP)
}
}

*/

/* startup_stm32f429_439xx.s
...
Heap_Size EQU 0x00800000

AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
...
*/

#include <stdio.h>
#include <stdlib.h>

#include "stm32f429i_discovery.h"
#include "stm32f429i_discovery_sdram.h"

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

int main(void)
{
char *p;

/* Make sure to initialize the external memory, pins and buses before using them */

/* SDRAM Initialization */
SDRAM_Init();

/* Disable write protection */
FMC_SDRAMWriteProtectionConfig(FMC_Bank2_SDRAM,DISABLE);

p = malloc(0x1000);

printf("Allocation at %p\n", p);

free(p);

while(1); // Don't want to exit
}

//******************************************************************************
// Hosting of stdio functionality through SWV - Serial Wire Viewer
//******************************************************************************

#include <rt_misc.h>

#pragma import(__use_no_semihosting_swi)

struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;

int fputc(int ch, FILE *f)
{
ITM_SendChar(ch);

return(ch);
}

int fgetc(FILE *f)
{
char ch;

ch = '?';

return((int)ch);
}

int ferror(FILE *f)
{
/* Your implementation of ferror */
return EOF;
}

void _ttywrch(int ch)
{
ITM_SendChar(ch);
}

void _sys_exit(int return_code)
{
label: goto label; /* endless loop */
}


#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

/* Infinite loop */
while (1)
{
}
}
#endif


Сейчас вроде все работает. Большое спасибо Golikov A. за помощь!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.