7

I'm working with an ARM Cortex M4 microcontroller that has a DMA, or peripheral DMA controller. One requirement of the DMA is that it cannot access pointers to addresses that exist in flash, but only pointers to addresses that are in RAM. Is there a way to determine if a particular pointer points to flash or RAM?

If not, I think I need to actually initialize a buffer in RAM then strcpy or something like that to transfer what is in flash into RAM so the DMA can read it. Does anyone know of a better way to do this so as not to waste CPU time if there is no way to tell if the pointer points to flash or RAM?

This is on an Atmel SAM4S.

Pugz
  • 821
  • 2
  • 10
  • 22

4 Answers4

5

You know the memory map of your microcontroller, so you can simply test your pointer against the start and end RAM addresses. In most cases your linkerscript will provide these addresses, so you don't need to type them in yourself (details will depends on yourlinkerscript). Note that wehen you use the linkerscript, the values won't be known at compilation time, so the compiler cannot optimize comparisions against know pointers.

Wouter van Ooijen
  • 48,407
  • 1
  • 63
  • 136
5

Main problem with checking whether a pointer is in specific range is unfortunately the C standard itself. Pointer arithmetic has a defined behaviour only if performed on pointers of the same type within the memory range of the same object (i.e. within the same allocated array range). A the comparison operators are defined as arithmetic operations, this restriction apply to them as well. A workaround for this problem would be casting the pointers to the uintptr_t type defined in stdint.h, which is an integer type guaranteed to hold a pointer value. And then perform your comparisons.

Now to the part of obtaining the right boundaries. Typically a C project would contain some kind of linker script defining memory regions of the specific architecture. Commonly it will include lines similar to the following:

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x40000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000
}

then, in the same script the following definitions can be added:

  _flash_start = ORIGIN(FLASH);
  _flash_end = ORIGIN(FLASH) + LENGTH(FLASH);

And then in C code these symbols can be accessed using:

extern int _flash_start ;  
extern int _flash_end;

And then a tricky part: The address of _flash_start will correspond to the flash starting address, and the address of _flash_end will correspond to the flash end address. I.e. the &_flash_start and &_flash_end are giving you the desired range.

Eugene Sh.
  • 9,986
  • 2
  • 26
  • 41
5

If your MCU follows the ARM Cortex conventions, you can look at the topmost nibble of the address in question:

int
inflash_p(void *addr)
{
    uintptr_t addr_int = addr;
    unsigned int addrtype = addr_int >> 28;

    // 0 = flash, 1,2 = ram, 4 = periph, e = system
    return (addrtype == 0);
}
corecode
  • 1,162
  • 8
  • 13
  • Thanks, I wasn't aware of that! What's the source of this, TRM? – domen Aug 21 '15 at 08:49
  • Sorry, I don't remember at the moment. When I come across it again, I will edit the answer. – corecode Aug 21 '15 at 15:56
  • 1+2 - what do you mean by that? Do you mean a return of 1 or 2 means it's in RAM, or 3 means it is in RAM? – Pugz Aug 24 '15 at 04:38
  • I think it means `0x10000000` - `0x2fffffff`, or said otherwise, every address that starts with nibble `1` or `2`. – domen Aug 24 '15 at 09:10
2

You can cast the pointer to an integer, then compare its value to the flash address space as defined in your MCU's memory map. For example, if your flash memory is at addresses 0x10000000 - 0x1001ffff, you could do:

void DMA_Function(uint8_t *ptr)
{
    uint32_t ptrAddress = (uint32_t)ptr;

    if (ptrAddress >= 0x10000000 && ptrAddress < 0x10020000)
        //The address is in flash
    else
        //The address is not in flash

    ...
}

Of course, in actual code it's better to use constants instead of hardcoded addresses -- FLASH_START_ADDR and FLASH_END_ADDR, for instance. If you want to be extra-flexible you can define linker variables for the flash addresses, which keeps the addresses out of your source code altogether.

Adam Haun
  • 21,331
  • 4
  • 50
  • 91