Forum: Mikrocontroller und Digitale Elektronik MSP430 IAR Error[e104]


von BL (Gast)


Lesenswert?

Hallo zusammen.

Ich nutze IAR Embeddet Workbench IDE V.5.20 und den µC MSP430F2013.

Ich bekomme folgenden Error:

Error[e104]: Failed to fit all segments into specified ranges. Problem 
discovered in segment CODE. Unable to place 25 block(s) (0x7bc byte(s) 
total) in 0x7b6 byte(s) of memory. The problem occurred while processing 
the


Heißt das mit anderen Worten, dass der µC stack voll ist?
Das wäre sehr krass, weil so viel Code habe ich noch gar nicht 
geschrieben.


Vielen Dank alle Hilfe. :)

BL

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

BL schrieb:
> Heißt das mit anderen Worten, dass der µC stack voll ist?
Nein, schlimmer: der Programmspeicher ist voll.

> weil so viel Code habe ich noch gar nicht geschrieben.
Zeig doch mal, was du hast. Als Dateianhang mit Nachmane *.c

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

BL schrieb:
> weil so viel Code habe ich noch gar nicht
> geschrieben.

Es reicht ja, wenn der von Dir geschriebene Code größere 
Libraryfunktionen einbindet -- der 'F2013 ist beispielsweise gar kein 
guter Kandidat für Floatingpoint-Arithmetik.
Mit nur 2 kiB Flash-ROM kann man keine großen Sprünge machen.

von BL (Gast)


Lesenswert?

ui ui ui ^^

Gibt es in IAR die Möglichkeit, die Größe des compilierten Codes zu 
sehen?

2 KB Flash Memory ist nicht viel, stimmt.

Als Code habe ich paar headerfiles mit defines drin und dann das 
USI_I2C.c file mit den state machines für den jeweiligen Befehl für das 
I2C Protokol.

Als kleines Beispiel:
1
int I2C_Write_1ByteRegister (int iCommand)
2
{
3
  static int siI2C_State = 0;
4
  int iNACK_Flag = 0;
5
  
6
  switch (siI2C_State)
7
  {
8
    case 0: //send start condition to slave
9
            USI_LOW_BYTE_SHIFT_REGISTER = SET_START;
10
            USI_CONTROL_REGISTER0 |= USI_LATCH_ENABLE + USI_DATA_OUTPUT_ENABLE;
11
            USI_CONTROL_REGISTER0 &= ~USI_LATCH_ENABLE;                    
12
            //send slave address to slave
13
            gcI2C_Slave_Address |= I2C_WRITE_TO_SLAVE_OPERATION;
14
            USI_LOW_BYTE_SHIFT_REGISTER = gcI2C_Slave_Address;       
15
            USI_BIT_COUNTER_REGISTER = USI_COMMUNICATION_BITS_8;            
16
            //set next state
17
            siI2C_State = 1;
18
            break;
19
            
20
    case 1: //receive address ACK / NACK
21
            USI_CONTROL_REGISTER0 &= ~USI_DATA_OUTPUT_ENABLE; 
22
            USI_BIT_COUNTER_REGISTER = USI_COMMUNICATION_BITS_1;
23
            //set next state
24
            siI2C_State = 2;            
25
            break;
26
            ...

Die state machines haben wohl den Speicher gefüllt?

von Karl H. (kbuchegg)


Lesenswert?

BL schrieb:

> USI_I2C.c file mit den state machines für den jeweiligen Befehl

#den# state machines?
Wieviele sind es denn?

Den Optimizer hast du aber schon eingeschaltet?

 für das
> I2C Protokol.
>
> Als kleines Beispiel:
>
>
1
> int I2C_Write_1ByteRegister (int iCommand)
2
> {
3
>   static int siI2C_State = 0;
4
>   int iNACK_Flag = 0;
5
> 
6
>   switch (siI2C_State)
7
>   {
8
>     case 0: //send start condition to slave
9
>             USI_LOW_BYTE_SHIFT_REGISTER = SET_START;
10
>             USI_CONTROL_REGISTER0 |= USI_LATCH_ENABLE +
11
> USI_DATA_OUTPUT_ENABLE;
12
>             USI_CONTROL_REGISTER0 &= ~USI_LATCH_ENABLE;
13
>             //send slave address to slave
14
>             gcI2C_Slave_Address |= I2C_WRITE_TO_SLAVE_OPERATION;
15
>             USI_LOW_BYTE_SHIFT_REGISTER = gcI2C_Slave_Address;
16
>             USI_BIT_COUNTER_REGISTER = USI_COMMUNICATION_BITS_8;
17
>             //set next state
18
>             siI2C_State = 1;
19
>             break;
20
> 
21
>     case 1: //receive address ACK / NACK
22
>             USI_CONTROL_REGISTER0 &= ~USI_DATA_OUTPUT_ENABLE;
23
>             USI_BIT_COUNTER_REGISTER = USI_COMMUNICATION_BITS_1;
24
>             //set next state
25
>             siI2C_State = 2;
26
>             break;
27
>             ...
28
>

Na ja. das sieht jetzt nur so weltbewegend aus. Aber im Grunde sind das 
nur ein paar Zuweisungen. Also nichts dramatisches. Das braucht ein paar 
Bytes, aber bis 2Kb ist da noch weit hin.

Such nach effektiven Berechnungen! Dort könnte was unbeabsichtigtes 
stecken. Oder tu das, was Lothar vorgeschlagen hat: Häng deinen verd.... 
Code hier an. Dann helfen wir dir das Zeug auf Kandidaten durchzusehen. 
Das ist doch nicht so schwer. Wenn du vom Arzt einen Rat willst, gehst 
du ja auch selber hin, damit er sich die Sache mal selber ansehen kann.

von BL (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> #den# state machines?
> Wieviele sind es denn?
Es sind 5 statemachines. Für jeden Befehl eine. Siehe Funktionen unten:

int I2C_SendCommand (int iCommand);
int I2C_Write_1ByteRegister (int iRegister);
int I2C_Write_2ByteRegister (int iRegister);
int I2C_Read_1ByteRegister (int iRegister);
int I2C_Read_2ByteRegister (int iRegister);


In der main ist einfach eine kleine while-Schleife mit Befehlen. Zum 
Beispiel:
1
      //config. temp. sensor
2
      giDS1621_Sensor_Register = DS1621_ACCESS_CONFIG;
3
      USICTL1 |= USIIFG;                 // Set flag and start communication
4
      LOW_POWER_MODE_1;
5
      __no_operation();
6
      Sleep(20);          //give sensor time to write to EEPROM
7
    
8
    if (giI2C_ERROR)
9
    {
10
      USI_ERROR ();
11
      break;
12
    }
13
        
14
    //start temp. conversion
15
    giDS1621_Sensor_Register = DS1621_START_CONVERSION;
16
    USICTL1 |= USIIFG;                 // Set flag and start communication
17
    LOW_POWER_MODE_1;
18
    __no_operation();  
19
    Sleep(10);
20
    if (giI2C_ERROR)
21
    {
22
      USI_ERROR ();
23
      break;
24
    }
25
    ...

Gibt es in IAR die Möglichkeit, die Größe des compilierten Codes zu
sehen?

von BL (Gast)


Lesenswert?

Ich habe nur eine Berechnungen:


giTimerA_Delay = (int)(iMilliseconds/500);


Alles andere sind Zuweisungen für Register.

von BL (Gast)


Lesenswert?

Ich habe jetzt unter "Optimizations" von Low auf High gestellt.
Jetzt scheint etwas mehr Platz zu sein. Der Fehler ist weg.

Würde aber gerne noch sehen, wieviel Platz denn da nun ist.

von Karl H. (kbuchegg)


Lesenswert?

BL schrieb:
> Ich habe jetzt unter "Optimizations" von Low auf High gestellt.
> Jetzt scheint etwas mehr Platz zu sein. Der Fehler ist weg.
>
> Würde aber gerne noch sehen, wieviel Platz denn da nun ist.

WIes beim IAR ist, weiß ich nicht.
Aber die übliche Bezeichnung dafür ist: Du willst ein Map erzeugt haben, 
oder Memory Map. Und die Option müsste sich irgendwo bei den Linker 
Optionen finden.

von BL (Gast)


Lesenswert?

Danke! Hab nun nen Map File erstellt. Ich schicks dir mal im Anhang.

Nach der Aussage des Files, verbrauche ich 1,5k ROM Speicher.

Mal suchen, was denn da soviel speicher frißt....


[Den Code selbst darf ich leider nicht senden. Sorry an alle!]

von Jörg S. (joerg-s)


Lesenswert?

Du kannst auch das untere Message Fenster so umstellen das mehr beim 
Build angezeigt wird.
Tool -> Options -> Messages -> Show build messages -> All

von BL (Gast)


Lesenswert?

ui stimmt.

Danke!

von BL (Gast)


Lesenswert?

Also falls noch jemand die Antwort wissen möchte:

Ich habe dem Code auf den Zahn gefühlt. Es sind tatsächlich die state 
machines. Benötigen 1k ROM Speicher. Können aber nicht kleiner 
programmiert
werden. Böse böse... ^^


Vielen Dank euch fürs Helfen!


BL

von mem saver (Gast)


Lesenswert?

BL schrieb:
> if (giI2C_ERROR)
>     {
>       USI_ERROR ();
>       break;
>     }

BL schrieb:
> __no_operation();
>     Sleep(10);

Wenn der ganze Code solche Dinge und weitere Überraschungen enthält, 
wundert mich dein Speicherproblem nicht.

von BL (Gast)


Lesenswert?

Wie bitte? ^^

Was soll an dem oberen Code überraschend oder schlecht programmiert 
sein?
Die Funktionsaufrufe???

von Optimizer (Gast)


Lesenswert?

BL schrieb:
> LOW_POWER_MODE_1;
>       __no_operation();
>       Sleep(20);          //give sensor time to write to EEPROM

kurze Fragen:
Warum wird mitten im Ablauf (keine Verzweigung) der Low Power Mode 
gewechselt?
Warum wird vor einem Delay ein NOP eingefügt?

>     if (giI2C_ERROR)
>     {
>       USI_ERROR ();
>       break;
>     }

weitere Frage:
Warum wird ein if Zweig am Ende unterbrochen?

Ja, ja, ich weiß, der Compiler optimiert das eine oder andere. Aber man 
sollte im Groben schon wissen, was man tut.

von Coder (Gast)


Lesenswert?

Das break dient, um aus der while-Schleife auszubrechen. Bevor man sich 
Gedanken, um Low Power macht, sollte erstmal das Programm funktionieren. 
Ein __no_operation gefolgt vom sleep ist natürlich unschön...

von BL (Gast)


Lesenswert?

Ihr solltet wissen, dass ihr euch grad über einen Code gedanken macht, 
der nur zu testzwecken geschrieben wurde, um das I2C Protokol zu testen 
und dann gelöscht wird.

Hier kurz die Erklärung:

Der Low-Power Mode wird nicht gewechselt.
__no_operation();   <-- Diese Zeile ist nur für die IAR Workbench 
gedacht. War in den Beispiel Codes von Texas Instruments so angegeben. 
Das ist aber kein Low-Power Mode für den µCs.

Sleep() <--  Sleep ist kein delay, sondern ein tatsächliches "sleep". 
Der µC geht da, der angegebenen Zeit entsprechend in Low-Power Mode und 
wird dann von einem Interrupt geweckt.

Die if-Abfragen sind in einer while-Schleife, die mehrere Befehle 
hintereinander ausführt. Entsteht zwischendrin ein Error, wird die 
gesamte
while-Schleife unterbrochen.

--------------------
Zusatz:  Also mein Speicherproblem ist ja im Grunde "behoben". Ich habe
1) die Optimierung von low auf high gesetzt
2) aus den 5 statemachines, eine gemacht.

Damit habe ich 800 bytes gesparrt. Meine Sleep Funktion frisst natürlich 
auch bytes, aber ich möchte sie trotzdem nicht durch eine delay funktion 
austauschen.

Danke für euer Interesse an meinem Problem! :)

von Optimizer (Gast)


Lesenswert?

BL schrieb:
> Ihr solltet wissen, dass ihr euch grad über einen Code gedanken macht,
> der nur zu testzwecken geschrieben wurde, um das I2C Protokol zu testen
> und dann gelöscht wird.

Sei doch froh, dass man es gut mit dir meint oder Mitleid hat. ;-D

BL schrieb:
> Der Low-Power Mode wird nicht gewechselt.
und was soll dann die Zeilen:
BL schrieb:
> LOW_POWER_MODE_1;

BL schrieb:
> __no_operation();   <-- Diese Zeile ist nur für die IAR Workbench
> gedacht. War in den Beispiel Codes von Texas Instruments so angegeben.
> Das ist aber kein Low-Power Mode für den µCs.
Du weisst nicht was NOP ist? LoL

BL schrieb:
> Sleep() <--  Sleep ist kein delay, sondern ein tatsächliches "sleep".
Das war nicht gemeint. Ein NOP vor einem Delay, Sleep oder was auch 
immer ist einfach Blödsinn.

BL schrieb:
> Die if-Abfragen sind in einer while-Schleife, die mehrere Befehle
> hintereinander ausführt. Entsteht zwischendrin ein Error, wird die
> gesamte
> while-Schleife unterbrochen.
Das hört sich nach einem halben goto an. ;-D
Meist lässt sich das durch else if lösen.

Du hast ein massives Programmspeicherproblem. In den gezeigten 
Codefragmenten sind mehere unnütze und verwirrende Anweisungen. Wie 
sieht der Rest wohl aus? Wahrscheinlich reicht ein 1k Flash. :-DDD

von BL (Gast)


Lesenswert?

Alter...

@Optimizer:
Hier der Original Code von Texas Instruments msp430x20x3_usi_06.c:
1
...
2
 while(1)
3
  {
4
    USICTL1 |= USIIFG;                 // Set flag and start communication
5
    LPM0;                              // CPU off, await USI interrupt
6
    _NOP();                            // Used for IAR
7
    for (i = 0; i < 5000; i++);        // Dummy delay between communication cycles
8
  }
9
...

Oh Wunder, da steht auch zuerst LPM0 und dann _NOP() ...
Was ist nun bitteschön falsch daran, diese beiden Zeilen in den eigenen 
Code zu übertragen????

Und als Kommentar zum NOP steht: USED for IAR.  Genau das hab ich oben 
geschrieben.

von panikplauze (Gast)


Lesenswert?

BL schrieb:
> Oh Wunder, da steht auch zuerst LPM0 und dann _NOP()

Ja ja, manche MSP's haben Probleme aus einem LPM wieder aufzuwachen wenn 
hinter der LPM-Anweisung kein NOP steht. Das kann also schon seinen Sinn 
haben, genaueres verrät das Datenblatt.

von Optimizer (Gast)


Lesenswert?

BL schrieb:
> Oh Wunder, da steht auch zuerst LPM0 und dann _NOP() ...
> Was ist nun bitteschön falsch daran, diese beiden Zeilen in den eigenen
> Code zu übertragen????

Dort wird auch ein Low Power Mode eingenommen, bis der direkt davor 
scharf gemachte USI Interrupt kommt. Wenn du es wie beim TI Beispiel 
machen möchtest, gehört NOP hinter dein Sleep.
Sei doch froh, dass man es dir erklärt, anstatt mit Unwissenheit zu 
pralen.

von BL (Gast)


Lesenswert?

@ panikplauze:
Danke :)

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.