STM32 и malloc во внешней памяти FMC / SDRAM

После того, как FMC/FSMC запустился и работает, внешняя память отражается по соответствующим адресам. Эту память можно использовать по захардкоденным адресам

char * ptr = (char*)0xC0000000;

но каждый раз вычислять адреса не комильфо. Тем более, для этого как раз есть специальная штука — heap и malloc/free.
Нужно только рассказать malloc где у нас эта память и сколько её. Самый простой способ — исправить правила линковки: Суть такова. _sbrk использует память начиная c адреса переданного линковщиком как end, стоит положить его адрес SDRAM, как malloc начинает раздавать адреса из неё.
например из соответствующих правил сборки грохнуть

PROVIDE( end = .)

и дописать свой:

end = 0xC000000;

Или добавить полноценно, в описании памяти добавить регион SDRAM

MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
SDRAM(rw)       : ORIGIN = 0xC0000000, LENGTH = 8M
}

и добавить секцию в раздел SECTIONS:

 ._user_heap(NOLOAD) :
  {
    PROVIDE(_heap_start = .);
    PROVIDE ( end = . );
    . += LENGTH(SDRAM);
    PROVIDE(_heap_end = .);
  }  >SDRAM

или (если не нравится, что size показывает дофига) без секции:

_heap_start = ORIGIN(SDRAM);
_heap_end = ORIGIN(SDRAM)+LENGTH(SDRAM);

А символы _heap_start и _heap_end будем использовать в своей реализации _sbrk, которая еще проверит не вылезаем ли мы за размер:

#include <stdlib.h>
#include <errno.h>
 
caddr_t _sbrk(int incr) {
    extern uint8_t _heap_start;
    extern uint8_t _heap_end;
 
    static uint8_t *current_end = NULL;
    uint8_t *current_block_address;
 
    if (!current_end)
        current_end = &_heap_start;
 
    current_block_address = current_end;
 
    incr = (incr + 3) & (~3);
    if (current_end + incr > &_heap_end) {
        errno = ENOMEM;
        return (caddr_t) -1;
    }
    current_end += incr;
    return (caddr_t) current_block_address;
 
}

Добавить комментарий