Cortex M0-hardfault bei Zugriff auf Variable

#5736429
Lesenswert?

Im Atmel Studio mit einem SAM21 Cortex M0 läuft das Programm in einen
hardfault wenn ein Zugriff auf eine Variable stattfindet.

Die Deklaration von xy_lcd_cursorPosition ist problemlos:
1
bla.c
2
#include "bla.h" 
3

4
//uint8_t  xy_lcd_cursorPosition __attribute__((aligned(4)))=0;
5
//uint32_t  xy_lcd_cursorPosition =0;
6
//uint8_t  xy_lcd_cursorPosition;
7
uint8_t  xy_lcd_cursorPosition=0;
8

9
static const __packed uint8_t ssd1306_font6x8 [] = 
10
{   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
11
    0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
12
...bla

Sobald aber ein Schreib(!)zugriff statt findet, läuft das Programm 
sofort beim Start in einen hardfault. Ohne Zugriff läuft das Programm:
1
status_code xy_lcd_init()
2
{   xy_lcd_cursorPosition=0;  //->HardFault
3
    //xy_lcd_cursorPosition=0;  //läuft

Ein Breakpoint bei
1
//startup_sam21.c
2
__libc_init_array();

geht. Danach im Disassembler weiter ist mühsam und bringt keine 
Erkenntnisse.
1
  __asm("BKPT #1\n") ; // Break into the debugger

R0 = 0x20000118
R1 = 0xfffffff9
R2 = 0x118
R3 = 0x9E9
R12 = 1
IPSRm = 3
APSR = 0x40000000
PSR = 0x40000003
AIRCR =0xfa050000
SCR = 0
CCR = 0x00000208

Übrigens, ein Breakpoint bei
1
status_code xy_lcd_init()
2
{   
3
-> xy_lcd_cursorPosition=0;  //->HardFault
wird nicht angelaufen.


Hat jemand eine Idee?
Besten Dank.
Gast #5737120
Lesenswert?

Thomas K. schrieb:
> __packed

Sehr verdächtig. Unaligned-Zugriffe gehen auf dem Cortex-M0 nicht 
(->Absturz). Benutzt du so etwas noch bei anderen Typen? Kompilierst du 
mit -munaligned-access?

Wie sehen die Register beim Hard Fault aus? Insbesondere das LR? Was 
steht im CFSR? Wie sieht der Assembler-Code an der Stelle, die im LR 
steht, aus?

Ansonsten Assembler Step-By-Step.
#5743751
Lesenswert?

Vielen Dank für die vielen Anregungen!

__packed
ist natürlich obsolet.


Im Watch war der erste Hinweis:
1
xy_lcd_cursorPosition  0x10  uint8_t(static storage at address 0x0)

address bei 0x0 ist Unsinn und Inhalt 0x10 ist verdächtig.

Das zentrale Problem war offenbar ein Durcheinander in der Make-Datei 
bzw. Müll im SolutionExplorer. Ich arbeite mit Links auf Dateien da die 
Sources für mehrerer Projekte verfügbar sein müssen. Da hatte sich tief 
versteckt ein Link auf eine alte *.c im Backup-Ordner eingeschlichen und 
die *.d und *.o-Files wollten sich auch nicht finden lassen.

Nach dem gründlichen Aufräumen des SolutionExplorer und Neustart(!) 
gehts:
1
xy_lcd_cursorPosition  0x00  uint8_t(static storage at address 0x20001048)

Es war also so, dass unbemerkt eine alte *.c, die nicht in das Projekt 
gehört, mit dem gleichen Namen wie die aktuelle *.cpp den Compiler an 
die Wand gespielt hat.
#5743759
Lesenswert?

Thomas K. schrieb:
> Ich arbeite mit Links auf Dateien da die
> Sources für mehrerer Projekte verfügbar sein müssen.

Damit zerschießt man sich make recht zuverlässig, da sich bei Links das 
Datum nicht ändert, wenn man das Original angefasst hat.

Du solltest also ein "make clean" in dein default Build Skript einbauen, 
denn so werden nur komplette rebuilds tun.
#5749174
Lesenswert?

Danke für die Tipps.

Auffällig ist, dass in der Funktion

syscalls.c
1
extern caddr_t _sbrk(int incr)
2
{  static unsigned char *heap = NULL;
3
  unsigned char *prev_heap;
4

5
  if (heap == NULL) {
6
    heap = (unsigned char *)&_end;
7
  }
8

9
  prev_heap = heap;
10

11
  heap += incr;
12

13
  return (caddr_t) prev_heap;
14
}

incr=0x9f8 und  heap=0x20007898

Dann ist nach
1
  heap += incr;
heap=0x20008290 und damit außerhalb des SRAM-Bereiches.
#5749209
Lesenswert?

Dr. Sommer schrieb:
> Vincent H. schrieb:
>> Bei der _sbrk Implementierung brennts auf einem M0 sowieso. Wenn "incr"
>> kein vielfaches von 4x ist dann verliert man das notwendige Alignment.
>
> Sollte nicht malloc dafür sorgen? Im Zweifelfall so aufrunden:
>
1
incr = (incr + 3) & 0xFFFFFFFC;

Hm, da bin ich mir nicht sicher. GNU MCU Ecplise etwa liefert in seiner 
newlib Variante genau das was du grad vorgeschlagen hast (inkl. Limit 
Prüfung):
1
caddr_t
2
_sbrk(int incr)
3
{
4
  extern char _Heap_Begin; // Defined by the linker.
5
  extern char _Heap_Limit; // Defined by the linker.
6

7
  static char* current_heap_end;
8
  char* current_block_address;
9

10
  if (current_heap_end == 0)
11
    {
12
      current_heap_end = &_Heap_Begin;
13
    }
14

15
  current_block_address = current_heap_end;
16

17
  // Need to align heap to word boundary, else will get
18
  // hard faults on Cortex-M0. So we assume that heap starts on
19
  // word boundary, hence make sure we always add a multiple of
20
  // 4 to it.
21
  incr = (incr + 3) & (~3); // align value to 4
22
  if (current_heap_end + incr > &_Heap_Limit)
23
    {
24
      // Some of the libstdc++-v3 tests rely upon detecting
25
      // out of memory errors, so do not abort here.
26
#if 0
27
      extern void abort (void);
28

29
      _write (1, "_sbrk: Heap and stack collision\n", 32);
30

31
      abort ();
32
#else
33
      // Heap has overflowed
34
      errno = ENOMEM;
35
      return (caddr_t) - 1;
36
#endif
37
    }
38

39
  current_heap_end += incr;
40

41
  return (caddr_t) current_block_address;
42
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren