I am using a K10DX128, there is 16 KB of RAM available total, according to the reference manual, the SRAM is split into SRAM_L and SRAM_U
But my linker script simply states that
RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K"
I have a bit of code that will malloc a piece of memory, by sheer coincidence, this bit of memory will occupy a bit of both regions. The memory contains an array of a struct, actually a list of files
This is a sample of my debug output as I am using memcpy to populate the file's information
file 1960 memcpy 0 addr 0x1FFFFCC0...done file 1970 memcpy 1 addr 0x1FFFFCE6...done file 1980 memcpy 2 addr 0x1FFFFD0C...done file misc2 memcpy 3 addr 0x1FFFFD32...done file 1990 memcpy 4 addr 0x1FFFFD58...done file ABC_YA~1 memcpy 5 addr 0x1FFFFD7E...done file AMBSTR~1 memcpy 6 addr 0x1FFFFDA4...done file amoeba memcpy 7 addr 0x1FFFFDCA...done file commod64 memcpy 8 addr 0x1FFFFDF0...done file CUBES_~1 memcpy 9 addr 0x1FFFFE16...done file EXPRIBB memcpy 10 addr 0x1FFFFE3C...done file finlshot memcpy 11 addr 0x1FFFFE62...done file GRAF_4KS memcpy 12 addr 0x1FFFFE88...done file haduken memcpy 13 addr 0x1FFFFEAE...done file intro memcpy 14 addr 0x1FFFFED4...done file kickstar memcpy 15 addr 0x1FFFFEFA...done file KS_HAL~1 memcpy 16 addr 0x1FFFFF20...done file KS_TOGET memcpy 17 addr 0x1FFFFF46...done file KSFINA~1 memcpy 18 addr 0x1FFFFF6C...done file KSHELLOS memcpy 19 addr 0x1FFFFF92...done file KSNINT memcpy 20 addr 0x1FFFFFB8...done file lavapixe memcpy 21 addr 0x1FFFFFDE... Exception Handler, source: 1 r0: 0x00000000, r1: 0x1FFFFA80, r2: 0x20000002, r3: 0x00000000, r12: 0x20001D8F LR: 0x0000482F, PC: 0x0000484C, PSR: 0x61000000,
notice how the memcpy failed for 0x1FFFFFDE , near the edge of the boundary.
then, I replaced memcpy with my own version, a trick to get my compiler to force 8 bit writes instead of 32 bit writes, it then works fine
_PTR memcpy_safe(void* dest, void* src, int cnt) { int start = (int)dest; int end = start + cnt; if (start <= 0x1FFFFFFF && end >= 0x20000000) // if memory lies over SRAM_L and SRAM_U boundary { volatile uint8_t useless = 0; // force 8 bit copy instead of optimized 32 bit copy volatile uint8_t c; volatile int i = 0; volatile uint8_t* src_p = (uint8_t*)src; volatile uint8_t* dest_p = (uint8_t*)dest; for (i = 0; i < cnt && useless == 0; i++) { c = src_p[i]; dest_p[i] = c; } } else { return memcpy(dest, src, cnt); } }
it works fine
file KSFINA~1 memcpy 18 addr 0x1FFFFF6C...done file KSHELLOS memcpy 19 addr 0x1FFFFF92...done file KSNINT memcpy 20 addr 0x1FFFFFB8...done file lavapixe memcpy 21 addr 0x1FFFFFDE...done file leon memcpy 22 addr 0x20000004...done file lilypad memcpy 23 addr 0x2000002A...done file LOGOAN01 memcpy 24 addr 0x20000050...done file LOGOAN02 memcpy 25 addr 0x20000076...done
so I then run this bit of code
volatile uint32_t* foo; foo = (volatile uint32_t*)0x1FFFFFFF; // right at the boundary between SRAM_L and SRAM_U *foo = 0x12345678; // perform a 32 bit write
bam! instant crash hard fault. this almost confirms my suspicion that the crash is caused by the boundary between SRAM_L and SRAM_U.
volatile uint32_t* foo; foo = (volatile uint32_t*)(0x1FFFFFFF - 4); *foo = 0x12345678;
this does not crash/hardfault
so my question is: is cross-boundary operations like this disallowed on K10 and K20 hardware?
how can I make sure that the compiler is aware of this? I am using GCC 4.7.2
I require "packed" because I need every single byte of RAM, the more the better, there's a file list that I need to sort and I want to sort as many as possible.
I do have a wrapper for malloc written to solve this problem (my fix is to assure properly aligned access by moving my pointer slightly by accounting for the size of my struct), but it only applies to Kinetis. No other family (STM, LPC, nRF, UC3, etc) that I've encountered seems to require this.
I cannot afford to use anything that is not GCC. I would appreciate it if somebody can provide a GCC compatible linker script that fixes this problem.
We ran into the same issue. We are using the GCC compiler.
Unfortunately I don't believe there is a simple linker script to fix this. The issue is with the Heap management code. It is expecting one linear block of ram for the heap allocation. The heap code has no way of allocating from 2 separate linker defined blocks of RAM. You would have to rewrite the heap management code to deal with this.
Our solution was to allocate a small heap object across the boundary and orphan it. This works for us since we are allocating and de-allocating a large number of same size small items. This would not work if you need to allocate a small number of very large items. It is similar to a heap fragmentation issue.
We're using C++. Attached is a snippet of what we did in C++. You should be quickly able to rewrite this in C if needed.
Is there a particular reason you can't just assure properly-aligned access, and avoid any hardware-level assembly (crossing boundaries)? If you don't force 'packed', a structure should naturally be assigned on access-sized boundaries. Surely MALLOC and subsequent MEMCPY can be constrained to 32bit boundaries.
> is cross-boundary operations like this disallowed on K10 and K20 hardware?
Essentially what is happening is you are crossing an AHB boundary (1KiB) to what end up being two separate slaves (SRAM_U and SRAM_L). With an appropriately designed master, the write could be split across the two slaves, in this case it seems the hardware is passing back some kind of error back. It's definitely not specific to the Kinetis in that sense, on other designs it may not present itself as a hard fault, but just hang the AHB bus instead.
The moral of the story is don't perform accesses across two slaves' boundaries on any ARM core.
Hi Frank,
Linker is not able to manage the 2 RAM block in Kinetis devices. When an object is allocated across the 2 blocks the application fails.
This is avoided by splitting the RAM segment into 2 segments on linker file. The idea would be that the linker would automatically distribute the RAM objects between the sections. Say filling up m_data and once full to fill up m_data2. Unfortunately Kinetis linker is not that smart, so as a user you need to manually distribute things editing the linker file.
Regards,
Carlos
Richard,
This is an issue that can happen with any tool provided the linker is written incorrectly. I my memory serves correctly, the IAR linker files already account for this and you should not see this issue in IAR as long as you are using one of our provided linker files.
Thanks,
Chris