hard fault caused by op near SRAM_L and SRAM_U boundary?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

hard fault caused by op near SRAM_L and SRAM_U boundary?

1,951 Views
frank26080115
Contributor II

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

Labels (1)
Tags (4)
0 Kudos
7 Replies

1,114 Views
frank26080115
Contributor II

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.

0 Kudos

1,114 Views
ndavies
Contributor V

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.

0 Kudos

1,113 Views
egoodii
Senior Contributor III

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.

0 Kudos

1,113 Views
matthewsealey
Contributor II

> 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.

0 Kudos

1,114 Views
Carlos_Musich
NXP Employee
NXP Employee

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

0 Kudos

1,114 Views
RichardR
Contributor IV

Is this an issue with CodeWarrior specifically, or will we see this using the IAR tools as well?

0 Kudos

1,114 Views
chris_brown
NXP Employee
NXP Employee

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

0 Kudos