Forum: Compiler & IDEs LPC1769 und Rowleys. Ist die main zu groß überscreibt er wahllos den Speicher


von Johannes V. (johannes_v)


Lesenswert?

Guten Tag,

Betreff sagt eigentlich schon fast alles.

Alles funtkioniert super, nur wenn ich in der main code einfüge hinter 
das printf, dann wird mir die SPeicherposition 0x100000f8 
kaputgeschrieben.
Dabei spielt es keine rolle welcher Wert dort steht.

Aufmerksam auf den Kern des Problems wurde ich erst als mir auffiel, 
dass die private member variable des Nunchuk nur einmal auf den I2C 
zugreifen kann bevor ihre Address Daten zerstört werde. Bzw, ist nicht 
ganz richtig. sie konnte nur einmal lesend zugreifen.

während System::init wird ein anderer I2C Sensor am selben Port mit der 
gleichen I2C klasse ausgelesen, alles funktioniert.

Bin das ganze jetzt schon zig mal durchgegangen, im Endeffekt kommt der 
Fehlzugriff während dem Intterrupt ansprung, also nicht davor oder 
danach, sondern während und auch nur wenn meine main "zu lang" ist.

ziemlich weit unten sieht man wie der IRQ verschatelt ist.

Ich weiss nicht mehr was ich machen soll ~_+ Hilfe
1
int main()
2
{
3
  System::init();
4
5
  Nunchuk::init();
6
7
  printf("done");
8
9
  short stick[3];
10
  float acc[3];
11
  int Power[3];
12
13
  while(1)
14
  {
15
    Nunchuk::read(acc, stick);
16
    printf("%f %f %f\n", acc[0], acc[1], acc[2]);
17
18
    Power[0] = acc[0] * 300 + 1500;
19
    PWM::set(Power[0], 1);
20
    Power[1] = acc[1] * 300 + 1500;
21
    PWM::set(Power[1], 2);
22
    Power[2] = acc[2] * 300 + 1500;
23
    PWM::set(Power[2], 3);
24
25
  }
26
  return 0;
27
}
1
class Nunchuk {
2
  static I2Cslot I2C;
3
  static unsigned char Stick_Zero[2];
4
  static short Acc_Zero[3];           <--- Die wird Im Moment zerstört
5
6
  static char raw(short *Acc, short *Stick);
7
8
  static inline short constrain(short &value, short &constr) {
9
    constr += NUNCHsmooth;
10
    if(value > constr)  return constr;
11
    constr -= (NUNCHsmooth << 1);
12
    if(value < constr)  return constr;
13
    return value; }
14
15
public:
16
17
  static int init();
18
19
  static char read(float *Acc, short *Stick);
20
};
1
#pragma once
2
3
class I2Cslot{
4
  unsigned char port;                   // holds port of this slot
5
  unsigned char address;                // holds address of this slot
6
7
  static unsigned char count;           // counts up through the bytes transmitted and received
8
  static unsigned char curadd;          // holds address of currently active slot
9
  static volatile unsigned char error;  // holds error code of currently active Port
10
  static unsigned char *pI2Cmsg;        // points on currently active I2C message
11
public:
12
  /*  Constructor to create slots for devices  */
13
  I2Cslot(unsigned char address, unsigned char port);
14
  /*  initializes all active I2C ports  */
15
  static int init();
16
  /*  IRQ to handle the transfers  */
17
  static void irq(unsigned int *pI2Cper);
18
  /*  send n bytes on this slot, n has to be in the first spot of the byte array pMsg points at */
19
  /*  returns 0 if no error occured of the transaction  */
20
  int send(unsigned char *pMsg);
21
  /*  receive n bytes on this slot, n has to be in the first spot of the byte array pMsg points at  */
22
  /*  returns 0 if no error occured of the transaction  */
23
  int rec(unsigned char *pMsg);
24
};
25
26
extern "C" {
27
void I2C0_IRQHandler(void);
28
void I2C1_IRQHandler(void);
29
void I2C2_IRQHandler(void);
30
}
1
int I2Cslot::send(unsigned char *pMsg)
2
{
3
  curadd = address;    //assign slot address
4
  pI2Cmsg = pMsg;      //assign message pointer
5
  unsigned int *pI2Cper = 0;
6
  int ttl = (pMsg[0] << 8);
7
  switch (port)
8
  {
9
#ifdef I2C0active
10
  case 0:
11
    pI2Cper = (unsigned int*)&LPC_I2C0->I2CONSET;
12
    break;
13
#endif
14
#ifdef I2C1active
15
  case 1:
16
    pI2Cper = (unsigned int*)&LPC_I2C1->I2CONSET;
17
    break;
18
#endif
19
#ifdef I2C2active
20
  case 2:
21
    pI2Cper = (unsigned int*)&LPC_I2C2->I2CONSET;
22
    break;
23
#endif
24
  default:
25
    return(1);
26
  }
27
28
#ifdef DEBUG
29
  printf("I2C%d: %d Bytes to %X\n", port, pI2Cmsg[0], curadd);
30
#endif
31
  error = 1;        //reset error
32
  count = 1;        //reset counter
33
34
>>>>> Hier ist noch alles i.O.  <<<<<<<
35
>>>>> Sobald der Porzess mit der nächsten Zeile in Gang gesetzt wird ist aber schluss, siehe IRQ.    <<<<<<<<<
36
37
  *pI2Cper = 0x20;    //generate start
38
  for(; ttl > 0; ttl--)  //check error status. stays 1 as long as the transmission isn't complete or the bus is in a good status
39
    if(!error)      //if the bus times out leave the loop
40
      break;
41
  if(error)
42
  {
43
    *pI2Cper = 0x10;  //generate a stop condition to recover bad bus and release it
44
#ifdef DEBUG
45
    printf("I2CError: %d\n", error);
46
#endif
47
  }
48
  return(error);      //error turns 0 if everything went well
49
}
50
51
52
int I2Cslot::rec(unsigned char *pMsg)
53
{
54
  address++;
55
  int temp = send(pMsg);
56
  address--;
57
  return (temp);
58
}
59
60
61
void I2Cslot::irq(unsigned int *pI2Cper)
62
{
63
 >>>> Hier ist der Fehlzugriff schon geschehen <<<<
64
65
  switch(*(pI2Cper+1))        //switch depending on currently active status register
66
  {
67
  case 0x08:              //start has been transmitted
68
    *(pI2Cper+2) = curadd;      //master receive -> address + 1
69
    *(pI2Cper+6) = 0x20;      //clear start
70
    break;
71
72
(..snip..)
73
74
void I2C1_IRQHandler( void )
75
{
76
>>>>>>>  Alles noch In Ordnung  <<<<<<
77
  I2Cslot::irq((unsigned int*)&LPC_I2C1->I2CONSET);
78
}

Ich vermute der Hund liegt irgendwo im stack vergraben, und das die 
Registersicherung nicht ganz einheitlich abläuft. Aber wieso das Problem 
erst bei längerer main auftritt, da bin ich einfach überfragt.

ich habe mal mit __attribute__((interrupt)) vor der C++ routine 
probiert, aber da ging dann gar nichts mehr.

Bin für jeden Tip dankbar, wenn mehr code gebraucht wird oder ich 
irgendwas ausprobieren soll, nur zu.

MfG
Johannes

von willibald (Gast)


Lesenswert?

Johannes V. schrieb:
> nur wenn meine main "zu lang" ist.

Das ist bestimmt nicht die Ursache, die liegt woanders.

_attribute_ ((interrupt)) gehört ggfs. an die Funktion 
I2C1_IRQHandler, aber auch da bin ich beim Cortex-M3 nicht ganz sicher.

Was anderes: Es kann sein, dass du für printf("%f") eine erweiterte 
Runtime-Lib dazulinken musst, hast du das gemacht? Ansonsten ersetz mal 
float acc[3] durch int acc[3] und printf("%f") durch printf("%d").

von (prx) A. K. (prx)


Lesenswert?

willibald schrieb:

> _attribute_ ((interrupt)) gehört ggfs. an die Funktion
> I2C1_IRQHandler, aber auch da bin ich beim Cortex-M3 nicht ganz sicher.

CM3 Interrupt Handler benötigen keinen speziellen Stackframe, sondern 
werden wie normale C Funktionen aufgerufen. Irgendwelche Attribute sind 
also nicht erforderlich.

von Johannes V. (johannes_v)


Lesenswert?

Hallo,

ich habe zwischenzeitlich den Interrupt jetzt einfach mit in die send()
eingebaut, da sie vorher ja auch nicht verlassen wurde während den 
wartezeiten.

Aber das ist ansich ja auf Dauer auch keine Lösung. Zum einen weil dann 
andere Intterrupts unter umständen meine SCL zu weit strecken (bleibt 
low sobald I2C irq flag steht) und zum anderen weil ich mir sicher bin, 
dass ich Interrupts noch brauchen werde sobald ich die RF12Bs zum laufen 
kriege.

_attribute_((irq)) habe ich auch probiert, aber das hat dann auch den 
aufruf komplett zu nichte gemacht und der controller geht in eine 
dauerschleife.

Also nochmal kurz und knapp, der Fehler kommt Zustande während dem 
Übergang vom C IRQ Handler der nichts anderes macht als den C++ IRQ 
Handler zu callen.

Dabei können auch andere I2C transfers vorher stattfinden ohne das der 
Speicher, oder zumindes was ich davon sehe, überrschrieben wird.

Zu Printf: in der tat muss man floatingpoint erst freischalten. habe ich 
auch gemacht und mittlerweile gibt er mir die messwerte auch 
entsprechend aus.

Das es nicht an einer zu großem main liegt ist mir auch klar, nur im 
ersten Atemzug ist das der zu beobachtende grund. Es muss irgendwas mit 
dem Übergang zwischen C und C++ zu tun haben. Ich gehe mittlerweile 
davon aus das ein weiterer Interrupt den ich in ähnlichem still betreibe 
auch irgendwo den Speicher überrschreibt, nur merkt man es nicht.

Wäre es denkbar die C++ IRQ Handler direkt in die Vectortabelle zu 
schreiben wenn innerhalb eh nur mit statischen variablen gearbeitet wird 
oder fehlt mir dann der this pointer?

Tut mir leid wenn das jetzt teilweise dumme fragen sind, aber ich habe 
auch erst vor 3 monaten angefangen mich intensiv mit programmieren zu 
beschäftigen.

von Peter D. (peda)


Lesenswert?

Johannes V. schrieb:
> Aufmerksam auf den Kern des Problems wurde ich erst als mir auffiel,
> dass die private member variable des Nunchuk nur einmal auf den I2C
> zugreifen kann bevor ihre Address Daten zerstört werde.

Ich kenne mich mit C++ nicht aus, aber unter C ist das klassisch ein 
Pointer, der in den Wald zeigt oder ein zu großes Displacement auf den 
Pointer.
So bequem Pointer auch sind, manchmal sollte man lieber einen Index 
nehmen. Ein Index läßt sich nämlich immer auf Gültigkeit prüfen, ein 
Pointer aber nicht.
Innerhalb einer Funktion kann man den Pointer überblicken. Aber 
funktionsübergreifend nehme ich lieber einen Index und jede Funktion 
prüft ihn bei Übergabe auf Gültigkeit.

Auch würde ich nicht gleich alle 3 I2C-Ports zusammen mengen, sondern 
erstmal nur ein I2C zum Laufen bringen.
Danach sollte man das doch einfach mit Vererbung auf 3 erweitern können.
Ständige Auswahlentscheidungen mit switch/case sind dann unnötig.


Johannes V. schrieb:
> Tut mir leid wenn das jetzt teilweise dumme fragen sind, aber ich habe
> auch erst vor 3 monaten angefangen mich intensiv mit programmieren zu
> beschäftigen.

Und dann gleich mit so einem Boliden anfangen, Hut ab.
Ich würde mir das nicht zutrauen.


Peter

von Peter (Gast)


Lesenswert?

Stack zu klein?

von Johannes V. (johannes_v)


Lesenswert?

Dürfte eigentlich nicht das Problem sein, 16kb hat er, und laut Rowleys 
verbrauche ich ca 500 byte.

Es läuft ja auch noch kein richtiges Programm, bin noch mit Treiber 
Entwicklung beschäftigt.

Einen exessiven Aufruf der mir den stack während der Laufzeit abschmatzt 
schließe ich auch aus, habe bis jetzt nicht einen rekursiven Aufruf und 
die tiefste Ebene müsste bei 3 liegen.

von Johannes V. (johannes_v)


Lesenswert?

Guten Tag,

das Problem saß natürlich vor dem Bildschirm.

Rowleys Crossworks bieted eine Schöne Ansicht des verwendeten Speichers 
mit farbigen Balken. Ich dachte es wäre eine Art "Real-Time" Anzeige.
Aber weit gefehlt, es zeigt nur an wie viel Stack und Heap der Linker 
zuteilt.

Und da waren dann wohl 128 byte doch zu knapp ~_^

Ich habe es noch nicht getested, nur gerade erfahren wie man das 
einstellen kann das er mehr Speicher reserviert.

Aber dazu eine andere Frage. Ich würde gerne eine ISR im Ram ablegen. 
Dazu eine neue Sektion im Linker eintragen und mit 
__attribute__((section"whatever")) die Funktion bereitstellen. Wird nach 
POR der code automatisch in den RAM copiert? Oder muss ich dann noch das 
startupscript manipulieren? Gibt es schon eine section die ich einfach 
mit nutzen könnte (fast_run z.b.)

MfG
Johannes

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.