I can read/write an external sdram using fmc in stm32f429. But working with address and read/write functions is not proper for my purpose. I want to introduce external sdram as if internal sram is clearly extended and whenever I define a big variable it is projected to external sdram automatically.
I checked stm32f4 cubemx repository examples (SDRAM+DATAMEMORY) and searched a lot but it seems this is not straightforward.
Following these steps based on what I found, I get hardfault after system_init.
Defining external sdram address and size in the linker (off-chip ram)
Adding some code in startup_stm32f420xx.s
Defining DATA_IN_ExtSDRAM for initializing sdram before main function
Enabling system clock before main function
My external sdram is connected to SDRAM1 in stm32f429.
What is the correct procedure? Is SystemInit_ExtMemCtl() function implemented correctly? Is any modification needed? Is enabling clock before main function and after system_init needed?
Can anyone tell what is the correct code step by step?
Thanks in advance.
What you are asking for is not really possible.
The internal SRAM and external SDRAM are not contiguous; their addresses are a long way apart and variables cannot simply overflow automatically from one to the other.
The correct steps for using the external memory are exactly as given in the example projects, it would be meaningless to repeat them here.
The work you have to do yourself is to decide which variables go in which memory. You can assign a variable to a section using the gcc section attribute or a similar feature of another compiler. There are examples of this in the STM32Cube package.
Related
I'm trying to read the memory of a Windows program based on a pointer I find by using ModuleInfo to get the address starting point and size of the module. But that pointer points to memory outside that modules address space, is there a way to find out the program uses that section of memory without having to find a pointer to it first?
See if the program in question has an interface ( https://en.m.wikipedia.org/wiki/Interface_(computing) ) that can be used to interface with said program. If there is no documented interface, attempting to tamper with that programs memory is a bad idea; and will most likely result in undefined behaviour. If this does not answer your question I suggest you edit it to specify exactly which program this is about.
For global offset table to work, GOT must be at a fixed location from text segment. Now assume that a program needs a shared library. Assume also that the shared library is already loaded by the OS for some other process. Now for our program, since text section of shared library is already loaded, it just needs to load data segment. The shared library text section is mapped back to the virtual address of our process. But what if there is already some data/text or whatever at the fixed offset from the virtual address of our shared library. How does the dynamic linker resolve that conflict? One approach would be to leave R_386_GOTPC in the text section till load time and let the dynamic linker change it the new offset. Is this how it is done in practice.
On GNU, even the same DSO is mapped at different addresses in different processes. No data at all is shared between them. This means that the GOT is just private data (like .data), and is initialized at load time with the proper addresses (either stubs or the proper function addresses with BIND_NOW).
(This assumes that prelink is not in use, which is somewhat broken anyway.)
We have a thesis project at work were the guys are trying to get external RAM to work for the STM32F417 MCU.
The project is trying out some stuff that is really resource hungry and the internal RAM just isn't enough.
The question is how to best do this.
The current approach has been to just replace the RAM address in the link script (gnu ld) with the address for external RAM.
The problem with that approach is that during initialisation, the chip has to run on internal RAM since the FSMC has not been initialized.
It seems to work but as soon as pvPortMalloc is run we get a hard fault and it is probably due to dereferencing bogus addresses, we can see that variables are not initialized correctly at system init (which makes sense I guess since the internal RAM is not used at all, when it probably should be).
I realize that this is a vague question, but what is the general approach when running code in external RAM on a Cortex M4 MCU, more specifically the STM32F4?
Thanks
FreeRTOS defines and uses a single big memory area for stack and heap management; this is simply an array of bytes, the size of which is specified by the configTOTAL_HEAP_SIZE symbol in FreeRTOSConfig.h. FreeRTOS allocates tasks stack in this memory area using its pvPortMalloc function, therefore the main goal here is to place the FreeRTOS heap area into external SRAM.
The FreeRTOS heap memory area is defined in heap_*.c (with the exception of heap_3.c that uses the standard library malloc and it doesn't define any custom heap area), the variable is called ucHeap. You can use your compiler extensions to set its section. For GCC, that would be something like:
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
Now we need to configure the linker script to place this custom section into external SRAM. There are several ways to do this and it depends again on the toolchain you're using. With GCC one way to do this would be to define a memory region for the SRAM and a section for ".sram_data" to append to the SRAM region, something like:
MEMORY
{
...
/* Define SRAM region */
sram : ORIGIN = <SRAM_START_ADDR>, LENGTH = <SRAM_SIZE>
}
SECTIONS
{
...
/* Define .sram_data section and place it in sram region */
.sram_data :
{
*(.sram_data)
} >sram
...
}
This will place the ucHeap area in external SRAM, while all the other text and data sections will be placed in the default memory regions (internal flash and ram).
A few notes:
make sure you initialize the SRAM controller/FSMC prior to calling any FreeRTOS function (like xTaskCreate)
once you start the tasks, all stack allocated variables will be placed in ucHeap (i.e. ext RAM), but global variables are still allocated in internal RAM. If you still have internal RAM size issues, you can configure other global variables to be placed in the ".sram_section" using compiler extensions (as shown for ucHeap)
if your code uses dynamic memory allocation, make sure you use pvPortMalloc/vPortFree, instead of the stdlib malloc/free. This is because only pvPortMalloc/vPortFree will use the ucHeap area in ext RAM (and they are thread-safe, which is a plus)
if you're doing a lot of dynamic task creation/deletion and memory allocation with pvPortMalloc/vPortFree with different memory block sizes, consider using heap_4.c instead of heap_2.c. heap_2.c has memory fragmentation problems when using several different block sizes, whereas heap_4.c is able to combine adjacent free memory blocks into a single large block
Another (and possibly simpler) solution would be to define the ucHeap variable as a pointer instead of an array, like this:
static uint8_t * const ucHeap = <SRAM_START_ADDR>;
This wouldn't require any special linker script editing, everything can be placed in the default sections. Note that with this solution the linker won't explicitly reserve any memory for the heap and you will loose some potentially useful information/errors (like heap area not fitting in ext RAM). But as long as you only have ucHeap in external RAM and you have configTOTAL_HEAP_SIZE smaller than external RAM size, that might work just fine.
When the application starts up it will try to initialise data by either clearing it to zero, or initialising it to a non-zero value, depending on the section the variable is placed in. Using a normal run time model, that will happen before main() is called. So you have something like:
1) Reset vector calls init code
2) C run time init code initialises variables
3) C run time init code calls main()
If you use the linker to place variables in external RAM then you need to ensure the RAM is accessible before that initialisation takes place, otherwise you will get a hard fault. Therefore you need to either have a boot loader that sets up the system for you, then starts your application....or more simply just edit the start up code to do the following:
1) Reset vector calls init code
2) >>>C run time init code configures external RAM<<<
3) C run time init code initialised variables
4) C run time init code calls main().
That way the RAM is available before you try to access it.
However, if all you want to do is have the FreeRTOS heap in external RAM, then you can leave the init code untouched, and just use an appropriate heap implementation - basically one that does not just declare a large static array. For example, if you use heap_5 then all you need to do is ensure the heap init function is called before any allocation is performed, because the heap init just describes which RAM to use as the heap, rather than statically declaring the heap.
I am working on a boot loader for TMS320DM6437. The idea is to create 2 independent firmware that one will update another. In firmware1 I will download firmware2 file and write it to NOR flash in a specified address. Both firmware are stored in NOR flash in ais format. Now I have two applications in flash. One is my custom boot loader and the second one is my main project. I want to know how I can jump from the first program to the second program located at a specified address. I also expect information about documents which may help me to create custom bootloader
Any recommendations?
You can jump to the entry point. I'm using this approach on TMS320 2802x and 2803x, but it should be the same.
The symbol of the entry point is c_int00.
To get to know the address of c_int00 in the second application, you have to fix the Run-Time Support (RTS) library at a specific address, by modifying the linker command file.
Otherwise you can leave the RTS unconstrained, and create a C variable (at a fixed address) that is initialized with the value of cint_00. Using this method your memory map is more flexible and you can add, togheter with the C variable, a comprehensive data structure with other information for your bootloader, e.g. CRC, version number, etc.
Be carefull with the (re)initialization of the peripherals in the second application, since you are not starting from a hardware reset, and you may need to explicity reset some more registers, or clear interrupt requests.
Here is my question,
I work on an application embeded in a board we manufactured ourselves for a space project.
The board uses a LEON2 Processor which is a derivate of SPARC v8 and we also use RTEMS as OS.
In this application we have to save default value for various tables for the FS in the EEPROM, so the user can modify them how he wants without having to do it everytime.
To achieve this I simply created a new section (.eeprom_data) and I placed it at address 0x6007cc40 which is in the EEPROM. It was done by using a specs file and a custom linker script which located the section at the correct address and told the compiler to put certain variables in this same section.
It seems to be working fine in this regard.
Here is an extract of objdump for the section and one particular var:
6 .eeprom_data 000033c0 6007cc40 6007cc40 00038a80 2**3
CONTENTS, ALLOC, LOAD, DATA
6007fbda g O .eeprom_data 00000002 Downlink_Priority_Vc1_default_value
The only problem is that it seems not to be fully working. My application runs correctly with no problem but doing a simple test like this only partially work:
Eeprom_ChipEnable(TRUE);
managed_faulty_sectors_default_crc = 0x789A;
tmp = managed_faulty_sectors_default_crc;
Eeprom_ChipEnable(FALSE);
The write operation which should write 0x789A in EEPROM does absolutely nothing
The read operation however works perfectly and returns correctly the data that is stored in the memory.
I don't really know how to solve this problem so I hope someone can give me a hand.
Thanks, Léo.
Thanks for your answers.
For some reason, when the HW engineer designed our board they did not allow the addressing of single 16 bits address only 32 bits address..
Are you sure the data cache (if any) is flushed before you disable the EEPROM?
And, are the EEPROM variables properly declared volatile?
Do you compile with optimization flags ?
I'd guess the compiler to optimize away the write unless managed_faulty_sectors_default_crc is declared volatile .
Also how is managed_faulty_sectors_default_crc mapped to the .eeprom_data section - does objdump give any clue as to wether they're mapped correctly ?