Forum: Compiler & IDEs Mega88 SPI Soft->Hard Jetzt Flash zu klein,HILFE


von Avr N. (balze)


Lesenswert?

Hallo zusammen,

ich bin dabei aus einem Mega88 , einem S65 Display und einer SD Karte 
einen digitalen Bilderrahmen zu bauen.
Meinem Projekt liegt der Code von Marc Meise zugrunde. (siehe hier: 
Beitrag "Re: Digitaler Bilderrahmen mit mega8 S65 Display und SD-Kart" )

Jetzt habe ich ein (Platz-)Problem beim Umstellen von Software- auf 
Hardware-SPI.

Kann mir das jemand erklären? Ich habe hier im Forum ausgiebig gesucht 
aber nichts ähnliches finden können.

Mein Problem ist folgendes:
Ich benutze am Mega88 sowohl die USART im SPI Modus, als auch den SPI 
Port.
Das S65 Display läuft mit Harware-SPI an der USART (PortD).

Die SPI Schnittstelle ist fuer Hardware SPI konfiguriert.
Ändere ich jetzt die Funktion zum Schreiben von Soft auf Hardware, passt 
es nicht mehr in den Flash :(

Also, dies hier:
1
uint8 SpiByte(unsigned char outbyte)
2
{
3
  uint8 a, inbyte=0, comp = 0x80;
4
  // use soft-SPI to be flexible with different pins and CPU types
5
  for (a=8; a>0; a--) //das Byte wird Bitweise nacheinander Gesendet MSB First
6
  {
7
    if (outbyte & comp)        //Ist Bit a in Byte gesetzt
8
    {
9
      MMC_PORT |= (1<<MMC_DO);   //Set Output High
10
    }
11
    else
12
    {
13
      MMC_PORT &= ~(1<<MMC_DO);   //Set Output Low
14
    }  
15
    MMC_PORT &= ~(1<<MMC_Clock);  //erzeugt ein Clock Impuls (LOW)
16
    asm volatile("nop");
17
    if (MMC_PIN & (1<<MMC_DI))     //Lesen des Pegels von MMC_DI
18
    {
19
      inbyte |= comp;
20
    }
21
    else
22
    {
23
      inbyte &=~comp;
24
    }
25
    MMC_PORT |= (1<<MMC_Clock);   //setzt Clock Impuls wieder auf (High)
26
    asm volatile("nop");
27
    comp >>= 1;
28
  }
29
  MMC_PORT |= (1<<MMC_DO);      //setzt Output wieder auf High  
30
  return inbyte;
31
}

tauschen gegen :
1
uint8 SpiByte(unsigned char outbyte)
2
{
3
  SPDR = outbyte;
4
  while(!(SPSR & (1 << SPIF)));
5
  SPSR &= ~(1 << SPIF);
6
  return SPDR;
}

Und ich bekomme die schoene Meldung region text is full :)
Mit SoftSPI (ohne HardwareSPI zu initialisieren) sind es nach dem 
Compilieren (mit -Os) 7910 bytes (96,6% Full)
Mit SoftSPI (MIT HardwareSPI Initialisierung) sind es nach dem 
Compilieren (mit -Os) 7920 bytes (96,7% Full)


Jede Hilfe ist willkommen !!

Schoenen Gruss,

Balze der AVR Noob

von holger (Gast)


Lesenswert?

>uint8 SpiByte(unsigned char outbyte)
>{
>  SPDR = outbyte;
>  while(!(SPSR & (1 << SPIF)));
>  SPSR &= ~(1 << SPIF);
>}

Der Aufruf einer Funktion mit Parameter
kostet dich mehr als wenn du das so machst:

 SPDR = outbyte;
 while(!(SPSR & (1 << SPIF)));

>  SPSR &= ~(1 << SPIF);

Und die Zeile hier drüber brauchst du nicht.

von Avr N. (balze)


Lesenswert?

Hallo nochmals,

holger wrote:
> Der Aufruf einer Funktion mit Parameter
> kostet dich mehr als wenn du das so machst:
>
>  SPDR = outbyte;
>  while(!(SPSR & (1 << SPIF)));

OK, das kann ich verstehen, allerdings ist es mit SoftSPI auch ein 
Funktionsaufruf mit Parametern. Wo ist der gravierende Unterschied 
zwischen Hard- und-Soft SPI bzgl. Speicherbedarf? Jemand eine Ahnung?

Ich habe mal alle Funktionsaufrufe durch das direkte Schreiben/Lesen der 
Register ersetzt, leider ohne Erfolg (bzgl. Speicherbedarf)

Kann mir jemand sagen, wie ich rausbekommen kann WIE GROSS der Flash den 
sein muesste? (Damit ich einen Anhaltspunkt bekomme, wo ich diese 
notwendige Reserve locker machen kann). Leider bekommt man ja keine 
Angaben mehr, sobald man den zulaessigen Flashbereich ueberschritten 
hat.
(Kann man das aus der Groesse des entstandenen HEX files ableiten? Ist 
ja anzunehmen, nur wie?)


holger wrote:
>>  SPSR &= ~(1 << SPIF);
>
> Und die Zeile hier drüber brauchst du nicht.

Diese Zeile ist aber NUR ueber, wenn man nach dem Lesen von SPSR AUCH 
auf SPDR zugreift, oder habe ich das Datenblatt falsch verstanden?

Vielen Dank, schoenen Gruss,

Balze, der AVR Noob

von Hmm... (Gast)


Lesenswert?

> Kann mir jemand sagen, wie ich rausbekommen kann WIE GROSS der Flash den
> sein muesste? (Damit ich einen Anhaltspunkt bekomme, wo ich diese
> notwendige Reserve locker machen kann). Leider bekommt man ja keine
> Angaben mehr, sobald man den zulaessigen Flashbereich ueberschritten
> hat.
> (Kann man das aus der Groesse des entstandenen HEX files ableiten? Ist
> ja anzunehmen, nur wie?)

Beim GCC (bzw WinAVR) liegt das schöne Tool 'size' bzw. 'avr-size' bei. 
Damit kannst du die größe der Binary-Datei (.elf) anzeigen lassen.


Ansonsten schau mal hier, ob du vielleicht auf andere Weise noch ein 
paar Bytes rausquetschen kannst:

http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung

von Jörg G. (joergderxte)


Lesenswert?

> Diese Zeile ist aber NUR ueber, wenn man nach dem Lesen von SPSR AUCH
> auf SPDR zugreift, oder habe ich das Datenblatt falsch verstanden?
machst du ja, mit "return SPDR;"

Probier doch, entweder:
1
/* Besonders gut, wenn die Funktion nur in einer Datei gebraucht wird, 
2
    oder in einem Header steht
3
*/
4
static uint8_t SpiByte(unsigned char outbyte)
5
{
6
    SPDR = outbyte;
7
    while(!(SPSR & (1 << SPIF)))
8
        ;
9
    return SPDR;
10
}
Oder (Es gibt auch noch einen -fnoinline... Parameter für den gcc, weiß 
ich aber nicht auswendig):
1
//Prototyp, gehoert eigentlich in eine header-Datei:
2
uint8 SpiByte(unsigned char outbyte) __attribute__((noinline));
3
/* das Attribut sorgt dafuer, dass die funktion IMMER aufgerufen wird
4
*/
5
uint8_t SpiByte(unsigned char outbyte)
6
{
7
    SPDR = outbyte;
8
    while(!(SPSR & (1 << SPIF)))
9
        ;
10
    return SPDR;
11
}
hth, Jörg

von Avr N. (balze)


Lesenswert?

Hallo zusammen,

@Hmm... :
Danke fuer den Tipp mit avr-size. Leider erstellt der Compiler aber 
scheinbar keine .elf (oder .hex ) Datei mehr, wenn er wegen eines zu 
kleinen Flash abbricht. Deshalb kann ich die Groesse doch nicht 
bestimmen. (Oder ich gehe da falsch ran, kann natuerlich sein, bin 
schliesslich der AVR Noob :)
Danke fuer den Link zur Optimierung, werde ich mir mal genauer ansehen! 
(Ich habe ehrlich gesagt gehofft, dass ich bei diesem Projekt nicht so 
tief einsteigen muss, bin eben noch ziemlich neu auf dem Gebiet)

@Jörg :
Danke fuer Deine Tipps!
Habe ich beides ausprobiert, leider auch ohne Erfolg.

Kann mir jemand erklaeren, warum der Code SOO gross wird mit Hardware 
SPI?

Wenn ich die Funktion so definiere:
1
uint8 SpiByte(unsigned char outbyte) 
2
{
3
/*  
4
    SPDR = outbyte;
5
    while(!(SPSR & (1 << SPIF)));
6
    return SPDR;
7
*/
8
while (outbyte-- != 0);
9
return outbyte;
10
}

Erhalte ich folgendes Ergebnis:
Program:    7432 bytes (90.7% Full)

Was ist so anders, wenn ich in einer Funktion auf Register zugreife ?

Irgendwie fuehle ich mich gerade dem Compiler ausgeliefert. :)

Immerhin zeigt sich, dass ich meinen Namen mit Bedacht gewaehlt habe :)

MfG,

Balze, der AVR Noob

von Jörg G. (joergderxte)


Lesenswert?

>  uint8 SpiByte(unsigned char outbyte)
>  {
>  ..snip..
>    while (outbyte-- != 0);
>  return outbyte;
>}

wird vom Compiler zu "return = 0;" optimiert und falls du den 
rückgabewert nicht verwendest, fliegt die Funktion ganz raus.
1
static uint8_t SpiByte(unsigned char outbyte)
2
{
3
    SPDR = outbyte;
4
    while(!(SPSR & (1 << SPIF)))
5
        ;
6
    return SPDR;
7
}
wird zu sowas wie:
1
  out     SPDR,   r24
2
1:
3
  sbis    SPSR,   SPIF
4
  rjmp    1b
5
  in      r24,    SPDR
aber die Funktion wird nie aufgerufen sondern immer in den Code 
kopiert (zumindest beim GCC >= 4.) - daher mein Versuch mit "noinline": 
ein simples "rcall SpiByte" ist noch kürzer als die ganze Funkition.

Wenn die Funktion nicht "static" ist, muss der Compiler (genau genommen 
der Linker) aber noch eine Kopie  behalten, falls die Funktion von 
außen doch noch aufgerufen wird (hier könnte der GCC-Parameter 
"-ffunction-sections" helfen, falls der noch nicht im Makefile (oder den 
AVR-Studioproject-settings) steht).

Vielleicht hilft dir noch AVR-GCC-Codeoptimierung, Aber mehr fällt 
mir auch jetzt nicht ein.
Schreib mal, welche GCC-Version du verwendest, evtl. helfen jakleine 
verbesserungen im Makefile noch ("-lm" "-fno-inline-small-functions",
"-fno-split-wide-types", "-fno-tree-scev-cprop", siehe hier: 
Beitrag "WinAvr 20080411 veröffentlicht" und hier 
Beitrag "Re: avr-gcc: 3.4.6 contra 4.3.0" )

hth, Jörg

von Helmut L. (helmi1)


Lesenswert?

Wenn der GCC die Funktion einfach mehrfach in den Code kopiert kann man 
die doch in ein separates File auslagern und sie im dem Programmteil wo 
sie gebraucht wird als "extern" deklarieren.
So ist der Compiler gezwungen die Funktion als Unterprogramm aufzurufen 
und nicht mehrfach in den Code zu kopieren.

Also lager die Funktion mal in eine andere 'C' Datei aus.

Gruss Helmi

von Avr N. (balze)


Lesenswert?

Helmut Lenzen wrote:
> Also lager die Funktion mal in eine andere 'C' Datei aus.

Helmi Du bist mein Held !  :)

Du hast Recht, jetzt funktioniert es !!!

Danke Euch alle, die Ihr mir geholfen habt!!

Jetzt kann es weitergehen.
Optimieren werde ich trotzdem noch muessen, damit ich das was ich 
vorhabe auch noch mit ins Flash bekomme. 8-0  ;-)

Danke nochmals, habe wieder eine Menge gelernt !

MfG,

Balze, der AVR Noob

von Helmut L. (helmi1)


Lesenswert?

Naja ab und zu muss man halt den Compiler zu seinem Glueck zwingen.

Schoen das es jetzt laeuft.

Gruss Helmi

von Avr N. (balze)


Lesenswert?

Helmut Lenzen wrote:
> Naja ab und zu muss man halt den Compiler zu seinem Glueck zwingen.

Naja ab und zu muss man einfach nur wissen wie es geht :) THX

Dafuer bin ich einfach ein (noch) zu schlechter C Programmierer.
Das moechte ich aber trotz meines Methusalem gleichen Alters noch 
aendern :)

@Jörg G.:
Ich habe WinAVR-20080512 installiert (gcc-4.3.0)
(Schon Lustig, habe das STK500 zu meinem Geburtstag 2008 bekommen und 
die Version von WinAVR ist nur 10 Tage juenger 8-0 )

Ich habe mir ehrlich gesagt keine grossen Gedanken um die Version der 
Entwicklungsumgebung gemacht, da ich angenommen habe, dass man mit der 
letzten nichts verkehrt macht. Ich haette es als Windows Nutzer 
eigentlich besser wissen muessen und die neue Version zumindest 
hinterfragen sollen. (Hab schliesslich auch kein Vista installiert :)

Nochmal Danke,

MfG,

Balze, der (stets bemuehte) AVR Noob :)

von Peter D. (peda)


Lesenswert?

Helmut Lenzen wrote:
> Also lager die Funktion mal in eine andere 'C' Datei aus.


Dann wirds aber schwierig mit der Registeroptimierung.
Besser also mit "-fno-inline-small-functions" dem GCC seine Inline-Sucht 
abzugewöhnen.


Ich würde aber für die Entwicklung zum ATmega328P raten (z.B. CSD).
Der hat auch noch doppelt SRAM (2kB), könnte für ein Filesystem ganz 
nützlich sein.


Peter

von Avr N. (balze)


Lesenswert?

@Peter:

Ja, ich habe auch schon ueber eine "groessere" Alternative nachgedacht.
In meinem (lokalen) Datenblatt vom Mega88 gibt es aber nur den Mega168, 
deshalb waere dieser meine Wahl gewesen, aber 2kByte SRAM waeren 
genial!!

Ist der 328P neu??

THX,

MfG,

Balze, der AVR Noob

P.S.: Hab gerade welche bestellt :) Meine Probleme werden kleiner :)

von Avr N. (balze)


Lesenswert?

Ich habe noch einen Helden : PETER   :)

Ich habe mal die von Dir vorgeschlagenen Compileroptionen eingestellt.
(Siehe hier: Beitrag "Re: avr-gcc: 3.4.6 contra 4.3.0" )

Und siehe da, auch ohne die Funktion in ein externes File auszulagern

Program:    7574 bytes (92.5% Full)

Dann hab ich ja wieder MASSENHAFT Platz :)

Danke,

mfG,

Balze, der AVR Noob

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.