mikrocontroller.net

Forum: Compiler & IDEs AVR und der Umgang mit C++


Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich beschäftige mich ein wenig mit C++ und Avr s.
Ich schreibe gerade an einer Classe, ich kann den Konstructor erzeugen 
aber der zugriff auf Methoden bleibt mir versperrt.
#include <stdio.h>

class RX5808 {
public:
    RX5808( void );
    void setFrequency( uint16_t frequency );
private:
    void setPIN(uint8_t pinNr, uint8_t state);
    void spi_1( void );
    void spi_0( void );
    void spiEnable( bool state );
    uint16_t calcFrequencyData( uint16_t frequency );
};
....

void init(void) {
    RX5808 rx();
    rx.setFrequency(0);
}

int main(void) {
  init();
    
    while(1)
    {

    }
  return 0; // never reached
}


bei rx.setFrequency(0)  kommt Request for member "setFrequency in "rx" 
which is non class typ RX5808()

Autor: Peter II (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
lass mal die klammer weg
RX5808 rx;

void spi_1( void );

bei C++ macht man das nicht mehr, wenn kein Parameter dann klammer leer 
lassen und nicht void reinschreiben

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich bei RX5808 rx(); die klammern weg lassen meckert der compile 
das an mit undefined reference to RX5808::RX5808()

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Das ist nicht der Compiler, das ist der Linker.

Und das ist kein Wunder; wo ist die Implementierung des Konstruktors? Du 
hast ihn nur deklariert ...

(Oder hast Du vergessen, das überflüssige "void" zu entfernen?)

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> Wenn ich bei RX5808 rx(); die klammern weg lassen meckert der compile
> das an mit undefined reference to RX5808::RX5808()

nein, das sagt der Linker.
Ist der Code in verschieden Dateien?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
/main.cpp
/src/"...h"
/src/"...cpp"

Alle libs(h und cpp) befinden sich in src

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> bei rx.setFrequency(0)  kommt Request for member "setFrequency in "rx"
> which is non class typ RX5808()

Rufus Τ. F. schrieb:
> Und das ist kein Wunder; wo ist die Implementierung des Konstruktors? Du
> hast ihn nur deklariert ...

Das reicht nicht aus.

Du must auch eine Instanz deiner Klasse anlegen.
Bisher hast du sie nur deklariert.

Also:
RX5808 rx;  // Objekt rx anlegen

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> Stefan schrieb:
>> Wenn ich bei RX5808 rx(); die klammern weg lassen meckert der compile
>> das an mit undefined reference to RX5808::RX5808()
>
> nein, das sagt der Linker.
> Ist der Code in verschieden Dateien?

Er (der Linker) hat zuvor nur deshalb nicht gemeckert, weil das schon 
der Compiler gemacht hat.
Ich vermute mal, der TO hat zuvor Java benutzt und stolpert gerade über 
die subtilen Unterschiede zwischen Java und C++. (hab nur gerade keine 
Zeit die runterzuschreiben)

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Du must auch eine Instanz deiner Klasse anlegen.

Das macht er:

Stefan schrieb:
> void init(void) {
>     RX5808 rx();
>     rx.setFrequency(0);
> }

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Das macht er:

... offensichtlich nicht, sonst würde init(void) die
Instanz ja kennen.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> ... offensichtlich nicht, sonst würde init(void) die
> Instanz ja kennen.

ein nicht-definierter Konstruktor ist der Grund für den Fehler. Wie 
Rufus schon schrieb.

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es macht übrigens auch wenig Sinn in dieser Funktion
void init(void)
{
    RX5808 rx();
    rx.setFrequency(0);
}

eine Instanz der Klasse anzulegen die global bekannt
sein soll ....

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Es macht übrigens auch wenig Sinn in dieser Funktion

> eine Instanz der Klasse anzulegen die global bekannt
> sein soll ....

wo steht das sie global bekannt sein soll?

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> wo steht das sie global bekannt sein soll?

Ja schon gut ... steht nirgends ....

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
STK500-Besitzer schrieb:
> ein nicht-definierter Konstruktor ist der Grund für den Fehler.

Ich hatte im Hinterkpf dass heutige c++ Compiler selbstständig
einen Konstruktor anlegen und bei Instanziierung durchlaufen
lassen, aber scheinbar ist dies beim GCC noch nicht der Fall.

Autor: STK5400-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Ich hatte im Hinterkpf dass heutige c++ Compiler selbstständig
> einen Konstruktor anlegen und bei Instanziierung durchlaufen
> lassen, aber scheinbar ist dies beim GCC noch nicht der Fall.

Ja, wenn er nicht deklariert wurde.

Autor: Arduinoquäler (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ohne weitere Worte. Siehe Source.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast das überflüssige "void" noch nicht aus Deiner Deklaration des 
Konstruktors entfernt.

>     RX5808 (void);

Mach das weg.

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Es macht übrigens auch wenig Sinn in dieser Funktion
>
>
> void init(void)
> {
>     RX5808 rx();
>     rx.setFrequency(0);
> }
> 
>
> eine Instanz der Klasse anzulegen die global bekannt
> sein soll ....

Es ist einfach so, daß in C++ der Default-Konstruktor, also der mit nur 
"()", ohne die beiden Klammer aufgerufen wird. Einfach nur der 
Varablennamen. Der Grund ist ganz einfach. So wie es oben steht, wird 
eine Funktion rx() definiert, die ein Objekt der Klasse RX5808 zurück 
liefert. Das war schon in C so und C++ sollte keine (all zu grossen) 
Semantik-Unterschiede aufweisen.
Also:
 RX5808 rx_variable;   // reserviere Platz und Rufe Default-Konstruktor
 RX5808 rx_function(); // "der linker wird eine Funktion rx_function
                       // finden, die ein RX5808 Objekt zurückgibt
Wenn man sich angewöhnt vor die Funktionsbekanntgabe "extern" zu 
schreiben, wenn man nicht gleich den Funktions-Body hinschreibt, erkennt 
man später schneller, was gemeint ist.

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Du hast das überflüssige "void" noch nicht aus Deiner Deklaration des
> Konstruktors entfernt.
>
>>     RX5808 (void);
>
> Mach das weg.

Sieht aber nur verwirrend aus, ist aus Sicht des Compilers aber korrekt. 
Ohne "void" ist eigentlich nur "Convenience"

Autor: tictactoe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C++ zum Programmieren von AVR zu verwenden halte ich prinzipiell für 
eine gute Idee. Mach ich selber auch so.

Meine Empfehlung allerdings: Nicht so:

Stefan schrieb:
> /main.cpp
> /src/"...h"
> /src/"...cpp"
>
> Alle libs(h und cpp) befinden sich in src

sondern schreibe sämtliche Implementierungen in die Header-Dateien (als 
inline Funktionen) und verzichte auf .cpp Dateien außer main.cpp. Dann 
kann der Compiler praktisch alles optimieren. Definiere weiters alle 
globalen Variablen mit 'static', damit sie auch wegoptimiert werden 
können.

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tictactoe schrieb:
> sondern schreibe sämtliche Implementierungen in die Header-Dateien (als
> inline Funktionen) und verzichte auf .cpp Dateien außer main.cpp. Dann
> kann der Compiler praktisch alles optimieren. Definiere weiters alle
> globalen Variablen mit 'static', damit sie auch wegoptimiert werden
> können.

der GCC hat schon eine weile die LTO Funktionalität, damit muss man 
nicht alles in eine Datei schreiben, nur wegen der Optimierung.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Sieht aber nur verwirrend aus, ist aus Sicht des Compilers aber korrekt.
> Ohne "void" ist eigentlich nur "Convenience"

Typisch für C++ Code ist (), während (void) als Relikt aus C Zeiten 
gilt.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Warum willst Du eigentlich überhaupt eine Instanz erzeugen nur um sie 
sofort hinterher wieder wegzuwerfen?

Wenn Deine "Methoden" alle keinen State brauchen dann brauchst Du auch 
keine Klassen und Instanzen sondern bestenfalls Namespaces und normale 
Funktionen.

: Bearbeitet durch User
Autor: tictactoe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> der GCC hat schon eine weile die LTO Funktionalität, damit muss man
> nicht alles in eine Datei schreiben, nur wegen der Optimierung.

Hab ich ausprobiert. Das Ergebnis ist WEIT hinter der 
alles-inline-Methode zurückgeblieben.

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tictactoe schrieb:
> Hab ich ausprobiert. Das Ergebnis ist WEIT hinter der
> alles-inline-Methode zurückgeblieben.

ich habe es selber noch nicht getestet, aber hast du auch das LTO bei 
Compiler und beim linker angeben? Sonst Funktioniert es nicht.

Autor: Kaj (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
tictactoe schrieb:
> Hab ich ausprobiert. Das Ergebnis ist WEIT hinter der
> alles-inline-Methode zurückgeblieben.
Gib doch mal Beispiel Code, anhand dessen wir alle das nachvollziehen 
können.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
tictactoe schrieb:
> Peter II schrieb:
>> der GCC hat schon eine weile die LTO Funktionalität, damit muss man
>> nicht alles in eine Datei schreiben, nur wegen der Optimierung.
>
> Hab ich ausprobiert. Das Ergebnis ist WEIT hinter der
> alles-inline-Methode zurückgeblieben.

Dann hast Du was falsch gemacht. Der Linker braucht dazu natürlich auch 
alle Optimierungsflags. Ich benutze das regelmäßig und kann schön 
beobachten wie er zum Beispiel Wrapper-Funktionen (zum Beispiel 
statische Callbacks) über zwei oder mehr Module hinweg problemlos 
inlined.

Seitdem hab ich keine Skrupel mehr zum Beispiel sowas zu schreiben:

// uart.c

void UART0_IRQHandler(void) {
    [...]
    uart_on_tx_disable();
    [...]
}
// foobus_master.c

/*
 * implement the callbacks from the UART driver
 */

void uart_on_tx_disable(void) {
    foobus_master_on_tx_disable();
}
// main.c

/*
 * implement the callbacks from the FOOBUS driver
 */

void foobus_master_on_tx_disable(void) {
    DE_low();
}
// gpio.h

static inline void DE_low(void) {
    DE_FPT->PCOR = DE_mask;
}

Das alles schrumpft durch LTO zusammen auf zwei ASM-Instruktionen im IRQ

: Bearbeitet durch User
Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Carl D. schrieb:
>> Sieht aber nur verwirrend aus, ist aus Sicht des Compilers aber korrekt.
>> Ohne "void" ist eigentlich nur "Convenience"
>
> Typisch für C++ Code ist (), während (void) als Relikt aus C Zeiten
> gilt.

Wir sind uns aber einig, daß beides die gleiche Bedeutung hat, oder?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Wir sind uns aber einig, daß beides die gleiche Bedeutung hat, oder?

Ja. Steht auch im Standard.

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> tictactoe schrieb:
>> Peter II schrieb:
>>> der GCC hat schon eine weile die LTO Funktionalität, damit muss man
>>> nicht alles in eine Datei schreiben, nur wegen der Optimierung.
>>
>> Hab ich ausprobiert. Das Ergebnis ist WEIT hinter der
>> alles-inline-Methode zurückgeblieben.
>
> Dann hast Du was falsch gemacht. Der Linker braucht dazu natürlich auch
> alle Optimierungsflags. Ich benutze das regelmäßig und kann schön
> beobachten wie er zum Beispiel Wrapper-Funktionen (zum Beispiel
> statische Callbacks) über zwei oder mehr Module hinweg problemlos
> inlined.
* implement the callbacks from the UART driver [/c]
> ...
> Das alles schrumpft durch LTO zusammen auf zwei ASM-Instruktionen im IRQ

kann ich zu hundert Prozent bestätigen.
Nur sollte man einen einigermaßen aktuellen Compiler haben (meiner nennt 
sich gerade 6.2, also nicht "sehr alt") und Compiler und Linker müssen 
mit "-Os -flto" gefüttert werden. Beide! Und mit der gleichen 
Optimierungsstufe.

Was dann herauskommt, mag von manchem Experten in Einzelfällen eleganter 
gemacht werden, aber nicht in 500ms. Wenn man z.B. feststellt, daß etwas 
anders gelayoutet ist oder sein sollte, oder low-active doch High-active 
sein soll.

Autor: Plopp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
>> Typisch für C++ Code ist (), während (void) als Relikt aus C Zeiten
>> gilt.
>
> Wir sind uns aber einig, daß beides die gleiche Bedeutung hat, oder?

Nur sicherheitshalber, falls jemand über den Thread stolpert und ihn nur 
grob überfliegt: In C++ ja, in C nein.
http://stackoverflow.com/questions/693788/is-it-be...

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So Hallo,

aktuell lag der Fehler im Makefile ich hab ihn aber noch nicht gefunden, 
jetzt sind alle Sources im ersten folder.
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "define.h"
#include "RX5808.h"

// declar


int main(void) {
    RX5808 rx;
    rx.setFrequency(0);
    while(1)
    {
//        _delay_ms(20);

        
    }

  return 0; // never reached
}


Das ist natürlich klar das rx nicht global definiert war und das war 
jetzt auch nicht das Problem.
Meine Version ist nicht ganz aktuell "avr-gcc (GCC) 4.9.3".
Natürlich braucht es keine Klasse, ich bin einfach nur am 
experimentieren was Sinn und Unsinn im bezug zu den Avr s macht. Die 
Antworten zum Thema optimieren gingen aber schon fast zu weit. Ich 
sollte also den ganzen Code in die .h Datei schreiben, das soll sinn 
machen wieso sollte der Compiler dann besser optimieren können ?

Ich poste gleich mal alles andere damit das hier komplett wird. Wenn ich 
alles richtig verstanden habe ....
class RX5808 {
public:
    RX5808();
    void setFrequency( uint16_t frequency );
private:
    void setPIN( uint8_t pinNr, uint8_t state );
    void spi_1();
    void spi_0();
    void spiEnable( bool state );
    uint16_t calcFrequencyData( uint16_t frequency );
};
// Digital pin definitions , software SPI
#define SPI_CLOCK_PIN       2
#define SLAVE_SELECT_PIN    3
#define SPI_DATA_PIN        4
#define LOW                 0
#define HIGH                1

//******************************************************************************
//* function: init SPI Pins
//******************************************************************************
void RX5808::Rx5808(){
    DDRD = (1<<SPI_CLOCK_PIN) | (1<<SLAVE_SELECT_PIN) | (1<<SPI_DATA_PIN);
}
//******************************************************************************
//* function: set SPI Pins
//******************************************************************************
void RX5808::setPIN( uint8_t pinNr, uint8_t state){
    if (state) {
        PORTD = 1<<pinNr ;
    }else{
        PORTD = 0<<pinNr ;
    }
}
//******************************************************************************
//* function: spi_1
//******************************************************************************
void RX5808::spi_1()
{
    
    setPIN(SPI_CLOCK_PIN, LOW);
    _delay_us(1);
    setPIN(SPI_DATA_PIN, HIGH);
    _delay_us(1);
    setPIN(SPI_CLOCK_PIN, HIGH);
    _delay_us(1);
    setPIN(SPI_CLOCK_PIN, LOW);
    _delay_us(1);
}

//******************************************************************************
//* function: spi_0
//******************************************************************************
void RX5808::spi_0()
{
    setPIN(SPI_CLOCK_PIN, LOW);
    _delay_us(1);
    setPIN(SPI_DATA_PIN, LOW);
    _delay_us(1);
    setPIN(SPI_CLOCK_PIN, HIGH);
    _delay_us(1);
    setPIN(SPI_CLOCK_PIN, LOW);
    _delay_us(1);
}

//******************************************************************************
//* function: spiEnableLow
//******************************************************************************
void RX5808::spiEnable(bool state)
{
    if (state) {
        _delay_us(1);
        setPIN(SLAVE_SELECT_PIN, HIGH);
        _delay_us(1);
        
    }else{
        _delay_us(1);
        setPIN(SLAVE_SELECT_PIN, LOW);
        _delay_us(1);
        
    }
}

//******************************************************************************
//* function: calcFrequencyData
//*         : calculates the frequency value for the syntheziser register B of
//*         : the RTC6751 circuit that is used within the RX5808/RX5880 modules.
//*         : this value is inteded to be loaded to register at adress 1 via SPI
//*         :
//*  Formula: frequency = ( N*32 + A )*2 + 479
//******************************************************************************
uint16_t RX5808::calcFrequencyData( uint16_t frequency )
{
    uint16_t N;
    uint8_t A;
    frequency = (frequency - 479) / 2;
    N = frequency / 32;
    A = frequency % 32;
    return (N << 7) |  A;
}

//******************************************************************************
//* function: setRTC6715Frequency
//*         : for a given frequency the register setting for synth register B of
//*         : the RTC6715 circuit is calculated and bitbanged via the SPI bus
//*         : please note that the synth register A is assumed to have default
//*         : values.
//*
//* SPI data: 4  bits  Register Address  LSB first
//*         : 1  bit   Read or Write     0=Read 1=Write
//*         : 13 bits  N-Register Data   LSB first
//*         : 7  bits  A-Register        LSB first
//******************************************************************************

void RX5808::setFrequency( uint16_t frequency){
    
    uint16_t sRegB;
    uint8_t i;
    
    sRegB = calcFrequencyData(frequency);
    
    // Bit bang the syntheziser register
    
    // Clock
    spiEnable(true);
    _delay_us(1);
    spiEnable(false);
    
    // Address (0x1)
    spi_1();
    spi_0();
    spi_0();
    spi_0();
    
    // Read/Write (Write)
    spi_1();
    
    // Data (16 LSB bits)
    for (i = 16; i; i--, sRegB >>= 1 ) {
        (sRegB & 0x1) ? spi_1() : spi_0();
    }
    // Data zero padding
    spi_0();
    spi_0();
    spi_0();
    spi_0();
    
    // Clock
    spiEnable(true);
    _delay_us(1);
    
    setPIN(SLAVE_SELECT_PIN, LOW);
    setPIN(SPI_CLOCK_PIN, LOW);
    setPIN(SPI_DATA_PIN, LOW);
}

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> if (state) {
>         PORTD = 1<<pinNr ;
>     }else{
>         PORTD = 0<<pinNr ;
>     }

also das ist mehr als falsch.

Willst du wirklich alle Bits auf dem Port ändern?
eine 0 kann man schieben wie man will, es bleibt eine 0.


Selbst wenn die Fehler weg sein, ist es sehr ungünstig für die Compiler. 
Weil er vermutlich nicht erkennt, das er den Port mit einer Bitoperation 
bearbeitet kann, es wird auf ein Read-Modify-Write hinauslaufen. Das ist 
langsam und kann ungewünschte Effekte erzeugen.

Es gibt gute gründe warum
[/c]
PORTD |= 1<<pinNr;
[c]
lieber als Makro verwendet wird, hier ist die Kapselung in Methoden 
nicht so einfach.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Peter II schrieb:
> Es gibt gute gründe warum [/c]
> PORTD |= 1<<pinNr;
> [c]
> lieber als Makro verwendet wird, hier ist die Kapselung in Methoden
> nicht so einfach.

Unterschätze nicht den Compiler. Wenn er beweisen kann daß pinNr 
konstant ist stehen die Chancen gut dass er an Ort und Stelle ein SBI 
einbaut anstelle eines Methodenaufrufs.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> Stefan schrieb:
>> if (state) {
>>         PORTD = 1<<pinNr ;
>>     }else{
>>         PORTD = 0<<pinNr ;
>>     }
>
> also das ist mehr als falsch.
>

Der Code ist noch nicht getestet, stimmt natürlich das war Blödsinn

void RX5808::setPIN( uint8_t pinNr, uint8_t state){
    if (state) {
        PORTD != (1<<pinNr) ;
    }else{
        PORTD &= ~(1<<pinNr) ;
    }
}

Aber es wäre besser als Makro ? Ich könnte mir vorstellen das es als 
Makro Performern wäre da es Inline ausgeführt wird. Bei der Funktion 
muss er sich erst mal die Sprungadresse merken und wieder zurück 
springen ?

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefan schrieb:
> Aber es wäre besser als Makro ? Ich könnte mir vorstellen das es als
> Makro Performern wäre da es Inline ausgeführt wird. Bei der Funktion
> muss er sich erst mal die Sprungadresse merken und wieder zurück
> springen ?

Beim C-Lernen auf einem AVR macht es Sinn sich die .lss-Datei 
anzuschauen. Da ist man doch (anfangs) überrascht, was der Compiler so 
produziert. Wenige können es (über alles betrachtet) besser und keiner 
von denen auch nur annähernd so schnell. Und viele Gerüchte erkennt man 
als solche.

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> Aber es wäre besser als Makro ?
> PORTD &= ~(1<<pinNr) ;

der Compiler muss erkennen das PinNr eine Konstante ist, dann wird 
daraus ein SetBit oder ClearBit. Wenn er das nicht erkennt dann wird das 
sehr umständlicher code.

erst wird 1<<PinNr ausgerechnet (was nur über eine schleife geht). Dann 
wird der Port gelesen, die oder Verknüpfung gemacht und dann wird das 
Ergebnis wieder in PortD geschrieben.


Bei einer Methode kann man sich kaum 100% darauf verlassen, das er es 
immer erkennt (hängt von viele Faktoren ab, ob es in der gleichen 
Übersetzungseinheit ist, wie oft die Methode verwendet wird usw.)

Vermutlich geht es dann auch nur mit Optimierung, wogegen es beim Makro 
immer funktioniert.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Stefan schrieb:
> Beim C-Lernen auf einem AVR macht es Sinn sich die .lss-Datei
> anzuschauen. Da ist man doch (anfangs) überrascht, was der Compiler so
> produziert. Wenige können es (über alles betrachtet) besser und keiner
> von denen auch nur annähernd so schnell. Und viele Gerüchte erkennt man
> als solche.

Gut ich hab mir die .lss jetzt mal angesehen und ehrlich gesagt auch das 
erste mal für mich sieht das jetzt aus wie der tatsächliche Assembler 
code nach der Optimierung ?

Builds/main.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000000  00800100  00000388  000003fc  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         00000388  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .stab         00001fec  00000000  00000000  000003fc  2**2
                  CONTENTS, READONLY, DEBUGGING
  3 .stabstr      00002079  00000000  00000000  000023e8  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .comment      00000011  00000000  00000000  00004461  2**0
                  CONTENTS, READONLY
  5 .debug_aranges 00000020  00000000  00000000  00004478  2**3
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_info   000000be  00000000  00000000  00004498  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_abbrev 00000014  00000000  00000000  00004556  2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_line   00000058  00000000  00000000  0000456a  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:  0c 94 34 00   jmp  0x68  ; 0x68 <__ctors_end>
   4:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
   8:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
   c:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  10:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  14:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  18:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  1c:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  20:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  24:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  28:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  2c:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  30:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  34:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  38:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  3c:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  40:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  44:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  48:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  4c:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  50:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  54:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  58:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  5c:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  60:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>
  64:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__bad_interrupt>

00000068 <__ctors_end>:
  68:  11 24         eor  r1, r1
  6a:  1f be         out  0x3f, r1  ; 63
  6c:  cf ef         ldi  r28, 0xFF  ; 255
  6e:  d8 e0         ldi  r29, 0x08  ; 8
  70:  de bf         out  0x3e, r29  ; 62
  72:  cd bf         out  0x3d, r28  ; 61
  74:  0e 94 b2 01   call  0x364  ; 0x364 <main>
  78:  0c 94 c2 01   jmp  0x384  ; 0x384 <_exit>

0000007c <__bad_interrupt>:
  7c:  0c 94 00 00   jmp  0  ; 0x0 <__vectors>

00000080 <_ZN6RX5808C1Ev>:

//******************************************************************************
//* function: init SPI Pins
//******************************************************************************
RX5808::RX5808(){
    DDRD = (1<<SPI_CLOCK_PIN) | (1<<SLAVE_SELECT_PIN) | (1<<SPI_DATA_PIN);
  80:  8c e1         ldi  r24, 0x1C  ; 28
  82:  8a b9         out  0x0a, r24  ; 10
  84:  08 95         ret

00000086 <_ZN6RX58086setPINEhh>:
}
//******************************************************************************
//* function: set SPI Pins
//******************************************************************************
void RX5808::setPIN( uint8_t pinNr, uint8_t state){
    if (state) {
  86:  44 23         and  r20, r20
  88:  49 f0         breq  .+18       ; 0x9c <_ZN6RX58086setPINEhh+0x16>
        PORTD = 1<<pinNr ;
  8a:  81 e0         ldi  r24, 0x01  ; 1
  8c:  90 e0         ldi  r25, 0x00  ; 0
  8e:  06 2e         mov  r0, r22
  90:  01 c0         rjmp  .+2        ; 0x94 <_ZN6RX58086setPINEhh+0xe>
  92:  88 0f         add  r24, r24
  94:  0a 94         dec  r0
  96:  ea f7         brpl  .-6        ; 0x92 <_ZN6RX58086setPINEhh+0xc>
  98:  8b b9         out  0x0b, r24  ; 11
  9a:  08 95         ret
    }else{
        PORTD = 0<<pinNr ;
  9c:  1b b8         out  0x0b, r1  ; 11
  9e:  08 95         ret

000000a0 <_ZN6RX58085spi_1Ev>:
  a0:  1b b8         out  0x0b, r1  ; 11
  #else
    //round up by default
    __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
  #endif

  __builtin_avr_delay_cycles(__ticks_dc);
  a2:  82 e0         ldi  r24, 0x02  ; 2
  a4:  8a 95         dec  r24
  a6:  f1 f7         brne  .-4        ; 0xa4 <_ZN6RX58085spi_1Ev+0x4>
  a8:  00 c0         rjmp  .+0        ; 0xaa <_ZN6RX58085spi_1Ev+0xa>
        PORTD = 1<<pinNr ;
  aa:  80 e1         ldi  r24, 0x10  ; 16
  ac:  8b b9         out  0x0b, r24  ; 11
  ae:  82 e0         ldi  r24, 0x02  ; 2
  b0:  8a 95         dec  r24
  b2:  f1 f7         brne  .-4        ; 0xb0 <_ZN6RX58085spi_1Ev+0x10>
  b4:  00 c0         rjmp  .+0        ; 0xb6 <_ZN6RX58085spi_1Ev+0x16>
  b6:  84 e0         ldi  r24, 0x04  ; 4
  b8:  8b b9         out  0x0b, r24  ; 11
  ba:  82 e0         ldi  r24, 0x02  ; 2
  bc:  8a 95         dec  r24
  be:  f1 f7         brne  .-4        ; 0xbc <_ZN6RX58085spi_1Ev+0x1c>
  c0:  00 c0         rjmp  .+0        ; 0xc2 <_ZN6RX58085spi_1Ev+0x22>
        PORTD = 0<<pinNr ;
  c2:  1b b8         out  0x0b, r1  ; 11
  c4:  82 e0         ldi  r24, 0x02  ; 2
  c6:  8a 95         dec  r24
  c8:  f1 f7         brne  .-4        ; 0xc6 <_ZN6RX58085spi_1Ev+0x26>
  ca:  00 c0         rjmp  .+0        ; 0xcc <_ZN6RX58085spi_1Ev+0x2c>
  cc:  08 95         ret

000000ce <_ZN6RX58085spi_0Ev>:
  ce:  1b b8         out  0x0b, r1  ; 11
  d0:  82 e0         ldi  r24, 0x02  ; 2
  d2:  8a 95         dec  r24
  d4:  f1 f7         brne  .-4        ; 0xd2 <_ZN6RX58085spi_0Ev+0x4>
  d6:  00 c0         rjmp  .+0        ; 0xd8 <_ZN6RX58085spi_0Ev+0xa>
  d8:  1b b8         out  0x0b, r1  ; 11
  da:  82 e0         ldi  r24, 0x02  ; 2
  dc:  8a 95         dec  r24
  de:  f1 f7         brne  .-4        ; 0xdc <_ZN6RX58085spi_0Ev+0xe>
  e0:  00 c0         rjmp  .+0        ; 0xe2 <_ZN6RX58085spi_0Ev+0x14>
        PORTD = 1<<pinNr ;
  e2:  84 e0         ldi  r24, 0x04  ; 4
  e4:  8b b9         out  0x0b, r24  ; 11
  e6:  82 e0         ldi  r24, 0x02  ; 2
  e8:  8a 95         dec  r24
  ea:  f1 f7         brne  .-4        ; 0xe8 <_ZN6RX58085spi_0Ev+0x1a>
  ec:  00 c0         rjmp  .+0        ; 0xee <_ZN6RX58085spi_0Ev+0x20>
        PORTD = 0<<pinNr ;
  ee:  1b b8         out  0x0b, r1  ; 11
  f0:  82 e0         ldi  r24, 0x02  ; 2
  f2:  8a 95         dec  r24
  f4:  f1 f7         brne  .-4        ; 0xf2 <_ZN6RX58085spi_0Ev+0x24>
  f6:  00 c0         rjmp  .+0        ; 0xf8 <_ZN6RX58085spi_0Ev+0x2a>
  f8:  08 95         ret

000000fa <_ZN6RX58089spiEnableEb>:
//******************************************************************************
//* function: spiEnableLow
//******************************************************************************
void RX5808::spiEnable(bool state)
{
    if (state) {
  fa:  66 23         and  r22, r22
  fc:  39 f0         breq  .+14       ; 0x10c <_ZN6RX58089spiEnableEb+0x12>
  fe:  82 e0         ldi  r24, 0x02  ; 2
 100:  8a 95         dec  r24
 102:  f1 f7         brne  .-4        ; 0x100 <_ZN6RX58089spiEnableEb+0x6>
 104:  00 c0         rjmp  .+0        ; 0x106 <_ZN6RX58089spiEnableEb+0xc>
        PORTD = 1<<pinNr ;
 106:  88 e0         ldi  r24, 0x08  ; 8
 108:  8b b9         out  0x0b, r24  ; 11
 10a:  05 c0         rjmp  .+10       ; 0x116 <_ZN6RX58089spiEnableEb+0x1c>
 10c:  82 e0         ldi  r24, 0x02  ; 2
 10e:  8a 95         dec  r24
 110:  f1 f7         brne  .-4        ; 0x10e <_ZN6RX58089spiEnableEb+0x14>
 112:  00 c0         rjmp  .+0        ; 0x114 <_ZN6RX58089spiEnableEb+0x1a>
        PORTD = 0<<pinNr ;
 114:  1b b8         out  0x0b, r1  ; 11
 116:  82 e0         ldi  r24, 0x02  ; 2
 118:  8a 95         dec  r24
 11a:  f1 f7         brne  .-4        ; 0x118 <_ZN6RX58089spiEnableEb+0x1e>
 11c:  00 c0         rjmp  .+0        ; 0x11e <_ZN6RX58089spiEnableEb+0x24>
 11e:  08 95         ret

00000120 <_ZN6RX580817calcFrequencyDataEj>:
//******************************************************************************
uint16_t RX5808::calcFrequencyData( uint16_t frequency )
{
    uint16_t N;
    uint8_t A;
    frequency = (frequency - 479) / 2;
 120:  6f 5d         subi  r22, 0xDF  ; 223
 122:  71 40         sbci  r23, 0x01  ; 1
 124:  cb 01         movw  r24, r22
 126:  96 95         lsr  r25
 128:  87 95         ror  r24
    N = frequency / 32;
    A = frequency % 32;
 12a:  28 2f         mov  r18, r24
 12c:  2f 71         andi  r18, 0x1F  ; 31
    N = frequency / 32;
 12e:  cb 01         movw  r24, r22
 130:  36 e0         ldi  r19, 0x06  ; 6
 132:  96 95         lsr  r25
 134:  87 95         ror  r24
 136:  3a 95         dec  r19
 138:  e1 f7         brne  .-8        ; 0x132 <_ZN6RX580817calcFrequencyDataEj+0x12>
    return (N << 7) |  A;
 13a:  96 95         lsr  r25
 13c:  98 2f         mov  r25, r24
 13e:  88 27         eor  r24, r24
 140:  97 95         ror  r25
 142:  87 95         ror  r24
}
 144:  82 2b         or  r24, r18
 146:  08 95         ret

00000148 <_ZN6RX580812setFrequencyEj>:
//*         : 1  bit   Read or Write     0=Read 1=Write
//*         : 13 bits  N-Register Data   LSB first
//*         : 7  bits  A-Register        LSB first
//******************************************************************************

void RX5808::setFrequency( uint16_t frequency){
 148:  ff 92         push  r15
 14a:  0f 93         push  r16
 14c:  1f 93         push  r17
 14e:  cf 93         push  r28
 150:  df 93         push  r29
 152:  ec 01         movw  r28, r24
    
    uint16_t sRegB;
    uint8_t i;
    
    sRegB = calcFrequencyData(frequency);
 154:  0e 94 90 00   call  0x120  ; 0x120 <_ZN6RX580817calcFrequencyDataEj>
 158:  8c 01         movw  r16, r24
 15a:  82 e0         ldi  r24, 0x02  ; 2
 15c:  8a 95         dec  r24
 15e:  f1 f7         brne  .-4        ; 0x15c <_ZN6RX580812setFrequencyEj+0x14>
 160:  00 c0         rjmp  .+0        ; 0x162 <_ZN6RX580812setFrequencyEj+0x1a>
        PORTD = 1<<pinNr ;
 162:  88 e0         ldi  r24, 0x08  ; 8
 164:  8b b9         out  0x0b, r24  ; 11
 166:  82 e0         ldi  r24, 0x02  ; 2
 168:  8a 95         dec  r24
 16a:  f1 f7         brne  .-4        ; 0x168 <_ZN6RX580812setFrequencyEj+0x20>
 16c:  00 c0         rjmp  .+0        ; 0x16e <_ZN6RX580812setFrequencyEj+0x26>
 16e:  82 e0         ldi  r24, 0x02  ; 2
 170:  8a 95         dec  r24
 172:  f1 f7         brne  .-4        ; 0x170 <_ZN6RX580812setFrequencyEj+0x28>
 174:  00 c0         rjmp  .+0        ; 0x176 <_ZN6RX580812setFrequencyEj+0x2e>
 176:  82 e0         ldi  r24, 0x02  ; 2
 178:  8a 95         dec  r24
 17a:  f1 f7         brne  .-4        ; 0x178 <_ZN6RX580812setFrequencyEj+0x30>
 17c:  00 c0         rjmp  .+0        ; 0x17e <_ZN6RX580812setFrequencyEj+0x36>
        PORTD = 0<<pinNr ;
 17e:  1b b8         out  0x0b, r1  ; 11
 180:  82 e0         ldi  r24, 0x02  ; 2
 182:  8a 95         dec  r24
 184:  f1 f7         brne  .-4        ; 0x182 <_ZN6RX580812setFrequencyEj+0x3a>
 186:  00 c0         rjmp  .+0        ; 0x188 <_ZN6RX580812setFrequencyEj+0x40>
    spiEnable(true);
    _delay_us(1);
    spiEnable(false);
    
    // Address (0x1)
    spi_1();
 188:  ce 01         movw  r24, r28
 18a:  0e 94 50 00   call  0xa0  ; 0xa0 <_ZN6RX58085spi_1Ev>
    spi_0();
 18e:  ce 01         movw  r24, r28
 190:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    spi_0();
 194:  ce 01         movw  r24, r28
 196:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    spi_0();
 19a:  ce 01         movw  r24, r28
 19c:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    
    // Read/Write (Write)
    spi_1();
 1a0:  ce 01         movw  r24, r28
 1a2:  0e 94 50 00   call  0xa0  ; 0xa0 <_ZN6RX58085spi_1Ev>
 1a6:  60 e1         ldi  r22, 0x10  ; 16
 1a8:  f6 2e         mov  r15, r22
    
    // Data (16 LSB bits)
    for (i = 16; i; i--, sRegB >>= 1 ) {
        (sRegB & 0x1) ? spi_1() : spi_0();
 1aa:  ce 01         movw  r24, r28
 1ac:  00 ff         sbrs  r16, 0
 1ae:  03 c0         rjmp  .+6        ; 0x1b6 <_ZN6RX580812setFrequencyEj+0x6e>
 1b0:  0e 94 50 00   call  0xa0  ; 0xa0 <_ZN6RX58085spi_1Ev>
 1b4:  02 c0         rjmp  .+4        ; 0x1ba <_ZN6RX580812setFrequencyEj+0x72>
 1b6:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    for (i = 16; i; i--, sRegB >>= 1 ) {
 1ba:  16 95         lsr  r17
 1bc:  07 95         ror  r16
 1be:  fa 94         dec  r15
 1c0:  a1 f7         brne  .-24       ; 0x1aa <_ZN6RX580812setFrequencyEj+0x62>
    }
    // Data zero padding
    spi_0();
 1c2:  ce 01         movw  r24, r28
 1c4:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    spi_0();
 1c8:  ce 01         movw  r24, r28
 1ca:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    spi_0();
 1ce:  ce 01         movw  r24, r28
 1d0:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
    spi_0();
 1d4:  ce 01         movw  r24, r28
 1d6:  0e 94 67 00   call  0xce  ; 0xce <_ZN6RX58085spi_0Ev>
 1da:  82 e0         ldi  r24, 0x02  ; 2
 1dc:  8a 95         dec  r24
 1de:  f1 f7         brne  .-4        ; 0x1dc <_ZN6RX580812setFrequencyEj+0x94>
 1e0:  00 c0         rjmp  .+0        ; 0x1e2 <_ZN6RX580812setFrequencyEj+0x9a>
        PORTD = 1<<pinNr ;
 1e2:  88 e0         ldi  r24, 0x08  ; 8
 1e4:  8b b9         out  0x0b, r24  ; 11
 1e6:  82 e0         ldi  r24, 0x02  ; 2
 1e8:  8a 95         dec  r24
 1ea:  f1 f7         brne  .-4        ; 0x1e8 <_ZN6RX580812setFrequencyEj+0xa0>
 1ec:  00 c0         rjmp  .+0        ; 0x1ee <_ZN6RX580812setFrequencyEj+0xa6>
 1ee:  82 e0         ldi  r24, 0x02  ; 2
 1f0:  8a 95         dec  r24
 1f2:  f1 f7         brne  .-4        ; 0x1f0 <_ZN6RX580812setFrequencyEj+0xa8>
 1f4:  00 c0         rjmp  .+0        ; 0x1f6 <_ZN6RX580812setFrequencyEj+0xae>
        PORTD = 0<<pinNr ;
 1f6:  1b b8         out  0x0b, r1  ; 11
 1f8:  1b b8         out  0x0b, r1  ; 11
 1fa:  1b b8         out  0x0b, r1  ; 11
    _delay_us(1);
    
    setPIN(SLAVE_SELECT_PIN, LOW);
    setPIN(SPI_CLOCK_PIN, LOW);
    setPIN(SPI_DATA_PIN, LOW);
}
 1fc:  df 91         pop  r29
 1fe:  cf 91         pop  r28
 200:  1f 91         pop  r17
 202:  0f 91         pop  r16
 204:  ff 90         pop  r15
 206:  08 95         ret

00000208 <_Z8spi_initv>:
void spi_init()
// Initialize pins for spi communication
{
//    DDRB &= ~((1<<MOSI)|(1<<MISO)|(1<<SS)|(1<<SCK));
    // Define the following pins as output
    DDRB |= ((1<<MOSI)|(1<<SS)|(1<<SCK)) | (1<<RESET);
 208:  84 b1         in  r24, 0x04  ; 4
 20a:  8d 62         ori  r24, 0x2D  ; 45
 20c:  84 b9         out  0x04, r24  ; 4
            (0<<SPIE)|              // SPI Interupt Enable
            (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
            (1<<MSTR)|              // Master/Slave select
            (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate
            (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
            (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)
 20e:  81 e5         ldi  r24, 0x51  ; 81
 210:  8c bd         out  0x2c, r24  ; 44
    
    SPSR = (1<<SPI2X);              // Double Clock Rate
 212:  81 e0         ldi  r24, 0x01  ; 1
 214:  8d bd         out  0x2d, r24  ; 45
    
    PORTB |= (1<<PB2);              //set SS to hight = deselected
 216:  2a 9a         sbi  0x05, 2  ; 5
 218:  08 95         ret

0000021a <_Z15spi_selectSlaveb>:
}

void spi_selectSlave(bool select){
    if( select ){
 21a:  88 23         and  r24, r24
 21c:  11 f0         breq  .+4        ; 0x222 <_Z15spi_selectSlaveb+0x8>
        PORTB &= ~(1<<PB2);          //set SS to low , selected
 21e:  2a 98         cbi  0x05, 2  ; 5
 220:  08 95         ret
    }else{
        PORTB |= (1<<PB2);
 222:  2a 9a         sbi  0x05, 2  ; 5
 224:  08 95         ret

00000226 <_Z17spi_transfer_syncPhS_h>:
    }
}

void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len)
// Shift full array through target device
{
 226:  26 2f         mov  r18, r22
    uint8_t i;
    for (i = 0; i < len; i++) {
 228:  fb 01         movw  r30, r22
 22a:  3e 2f         mov  r19, r30
 22c:  32 1b         sub  r19, r18
 22e:  34 17         cp  r19, r20
 230:  50 f4         brcc  .+20       ; 0x246 <_Z17spi_transfer_syncPhS_h+0x20>
        SPDR = dataout[i];
 232:  dc 01         movw  r26, r24
 234:  3d 91         ld  r19, X+
 236:  cd 01         movw  r24, r26
 238:  3e bd         out  0x2e, r19  ; 46
        while((SPSR & (1<<SPIF))==0);
 23a:  0d b4         in  r0, 0x2d  ; 45
 23c:  07 fe         sbrs  r0, 7
 23e:  fd cf         rjmp  .-6        ; 0x23a <_Z17spi_transfer_syncPhS_h+0x14>
        datain[i] = SPDR;
 240:  3e b5         in  r19, 0x2e  ; 46
 242:  31 93         st  Z+, r19
 244:  f2 cf         rjmp  .-28       ; 0x22a <_Z17spi_transfer_syncPhS_h+0x4>
    }
}
 246:  08 95         ret

00000248 <_Z17spi_transmit_syncPhh>:

void spi_transmit_sync (uint8_t * dataout, uint8_t len)
// Shift full array to target device without receiving any byte
{
 248:  28 2f         mov  r18, r24
    uint8_t i;
    for (i = 0; i < len; i++) {
 24a:  fc 01         movw  r30, r24
 24c:  8e 2f         mov  r24, r30
 24e:  82 1b         sub  r24, r18
 250:  86 17         cp  r24, r22
 252:  30 f4         brcc  .+12       ; 0x260 <_Z17spi_transmit_syncPhh+0x18>
        SPDR = dataout[i];
 254:  81 91         ld  r24, Z+
 256:  8e bd         out  0x2e, r24  ; 46
        while((SPSR & (1<<SPIF))==0);
 258:  0d b4         in  r0, 0x2d  ; 45
 25a:  07 fe         sbrs  r0, 7
 25c:  fd cf         rjmp  .-6        ; 0x258 <_Z17spi_transmit_syncPhh+0x10>
 25e:  f6 cf         rjmp  .-20       ; 0x24c <_Z17spi_transmit_syncPhh+0x4>
    }
}
 260:  08 95         ret

00000262 <_Z14spi_fast_shifth>:

uint8_t spi_fast_shift (uint8_t data)
// Clocks only one byte to target device and returns the received one
{
    SPDR = data;
 262:  8e bd         out  0x2e, r24  ; 46
    while((SPSR & (1<<SPIF))==0);
 264:  0d b4         in  r0, 0x2d  ; 45
 266:  07 fe         sbrs  r0, 7
 268:  fd cf         rjmp  .-6        ; 0x264 <_Z14spi_fast_shifth+0x2>
    return SPDR;
 26a:  8e b5         in  r24, 0x2e  ; 46
 26c:  08 95         ret

0000026e <_ZN7Max74564initEv>:

//-----------------------------------------------------------------------------
// Implements Max7456::init
//-----------------------------------------------------------------------------
void Max7456::init( void )
{
 26e:  ef 92         push  r14
 270:  ff 92         push  r15
 272:  0f 93         push  r16
 274:  1f 93         push  r17
 276:  cf 93         push  r28
 278:  df 93         push  r29
 27a:  ec 01         movw  r28, r24
    _isActivatedOsd = false;
 27c:  19 82         std  Y+1, r1  ; 0x01
    
    _regVm1.whole = 0b01000111;
 27e:  87 e4         ldi  r24, 0x47  ; 71
 280:  8b 83         std  Y+3, r24  ; 0x03
    spi_init();
 282:  0e 94 04 01   call  0x208  ; 0x208 <_Z8spi_initv>
  __builtin_avr_delay_cycles(__ticks_dc);
 286:  8f e3         ldi  r24, 0x3F  ; 63
 288:  9c e9         ldi  r25, 0x9C  ; 156
 28a:  01 97         sbiw  r24, 0x01  ; 1
 28c:  f1 f7         brne  .-4        ; 0x28a <_ZN7Max74564initEv+0x1c>
 28e:  00 c0         rjmp  .+0        ; 0x290 <_ZN7Max74564initEv+0x22>
 290:  00 00         nop
    _delay_ms(20);

    spi_selectSlave(true);
 292:  81 e0         ldi  r24, 0x01  ; 1
 294:  0e 94 0d 01   call  0x21a  ; 0x21a <_Z15spi_selectSlaveb>
    spi_fast_shift(VM0_ADDRESS_WRITE);
 298:  80 e0         ldi  r24, 0x00  ; 0
 29a:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
    
    _regVm0.whole = 0x00;
    _regVm0.bits.videoSelect=1; //PAL
    _regVm0.bits.softwareResetBit = 1;
 29e:  82 e4         ldi  r24, 0x42  ; 66
 2a0:  8a 83         std  Y+2, r24  ; 0x02
    spi_fast_shift(_regVm0.whole);
 2a2:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
    spi_selectSlave(false);
 2a6:  80 e0         ldi  r24, 0x00  ; 0
 2a8:  0e 94 0d 01   call  0x21a  ; 0x21a <_Z15spi_selectSlaveb>
 2ac:  ef e3         ldi  r30, 0x3F  ; 63
 2ae:  fc e9         ldi  r31, 0x9C  ; 156
 2b0:  31 97         sbiw  r30, 0x01  ; 1
 2b2:  f1 f7         brne  .-4        ; 0x2b0 <_ZN7Max74564initEv+0x42>
 2b4:  00 c0         rjmp  .+0        ; 0x2b6 <_ZN7Max74564initEv+0x48>
 2b6:  00 00         nop
    _delay_ms(20);
    
    spi_selectSlave(true);
 2b8:  81 e0         ldi  r24, 0x01  ; 1
 2ba:  0e 94 0d 01   call  0x21a  ; 0x21a <_Z15spi_selectSlaveb>
    for(int x = 0 ; x < 16 ; x++)
 2be:  00 e0         ldi  r16, 0x00  ; 0
 2c0:  10 e0         ldi  r17, 0x00  ; 0
 2c2:  7e 01         movw  r14, r28
 2c4:  e0 0e         add  r14, r16
 2c6:  f1 1e         adc  r15, r17
    {
        _regRb[x].whole = 0x00;
        _regRb[x].bits.characterWhiteLevel = 2;
 2c8:  82 e0         ldi  r24, 0x02  ; 2
 2ca:  f7 01         movw  r30, r14
 2cc:  87 87         std  Z+15, r24  ; 0x0f
        spi_fast_shift(x+RB0_ADDRESS_WRITE);
 2ce:  80 e1         ldi  r24, 0x10  ; 16
 2d0:  80 0f         add  r24, r16
 2d2:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
        spi_fast_shift(_regRb[x].whole);
 2d6:  f7 01         movw  r30, r14
 2d8:  87 85         ldd  r24, Z+15  ; 0x0f
 2da:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
    for(int x = 0 ; x < 16 ; x++)
 2de:  0f 5f         subi  r16, 0xFF  ; 255
 2e0:  1f 4f         sbci  r17, 0xFF  ; 255
 2e2:  00 31         cpi  r16, 0x10  ; 16
 2e4:  11 05         cpc  r17, r1
 2e6:  69 f7         brne  .-38       ; 0x2c2 <_ZN7Max74564initEv+0x54>
    }
    
    _regVm0.whole = 0x00;
    
    _regVm0.bits.verticalSynch = 1;
 2e8:  84 e0         ldi  r24, 0x04  ; 4
 2ea:  8a 83         std  Y+2, r24  ; 0x02
    
    spi_fast_shift(VM0_ADDRESS_WRITE);
 2ec:  80 e0         ldi  r24, 0x00  ; 0
 2ee:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
    
    spi_fast_shift(_regVm0.whole);
 2f2:  8a 81         ldd  r24, Y+2  ; 0x02
 2f4:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
    //
    //  digitalWrite(_pinCS,LOW);
    //SPI.transfer(VM1_ADDRESS_WRITE);
    //SPI.transfer(0x0C);
    
    spi_selectSlave(false);
 2f8:  80 e0         ldi  r24, 0x00  ; 0
}
 2fa:  df 91         pop  r29
 2fc:  cf 91         pop  r28
 2fe:  1f 91         pop  r17
 300:  0f 91         pop  r16
 302:  ff 90         pop  r15
 304:  ef 90         pop  r14
    spi_selectSlave(false);
 306:  0c 94 0d 01   jmp  0x21a  ; 0x21a <_Z15spi_selectSlaveb>

0000030a <_ZN7Max745611activateOSDEb>:
 30a:  0f 93         push  r16
 30c:  1f 93         push  r17
 30e:  cf 93         push  r28
 310:  df 93         push  r29
 312:  1f 92         push  r1
 314:  cd b7         in  r28, 0x3d  ; 61
 316:  de b7         in  r29, 0x3e  ; 62
 318:  8c 01         movw  r16, r24
 31a:  fc 01         movw  r30, r24
 31c:  81 81         ldd  r24, Z+1  ; 0x01
 31e:  86 17         cp  r24, r22
 320:  d9 f0         breq  .+54       ; 0x358 <_ZN7Max745611activateOSDEb+0x4e>
 322:  82 81         ldd  r24, Z+2  ; 0x02
 324:  80 64         ori  r24, 0x40  ; 64
 326:  82 83         std  Z+2, r24  ; 0x02
 328:  66 23         and  r22, r22
 32a:  11 f0         breq  .+4        ; 0x330 <_ZN7Max745611activateOSDEb+0x26>
 32c:  88 60         ori  r24, 0x08  ; 8
 32e:  02 c0         rjmp  .+4        ; 0x334 <_ZN7Max745611activateOSDEb+0x2a>
 330:  87 7f         andi  r24, 0xF7  ; 247
 332:  f8 01         movw  r30, r16
 334:  82 83         std  Z+2, r24  ; 0x02
 336:  81 e0         ldi  r24, 0x01  ; 1
 338:  69 83         std  Y+1, r22  ; 0x01
 33a:  0e 94 0d 01   call  0x21a  ; 0x21a <_Z15spi_selectSlaveb>
 33e:  80 e0         ldi  r24, 0x00  ; 0
 340:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
 344:  f8 01         movw  r30, r16
 346:  82 81         ldd  r24, Z+2  ; 0x02
 348:  0e 94 31 01   call  0x262  ; 0x262 <_Z14spi_fast_shifth>
 34c:  80 e0         ldi  r24, 0x00  ; 0
 34e:  0e 94 0d 01   call  0x21a  ; 0x21a <_Z15spi_selectSlaveb>
 352:  69 81         ldd  r22, Y+1  ; 0x01
 354:  f8 01         movw  r30, r16
 356:  61 83         std  Z+1, r22  ; 0x01
 358:  0f 90         pop  r0
 35a:  df 91         pop  r29
 35c:  cf 91         pop  r28
 35e:  1f 91         pop  r17
 360:  0f 91         pop  r16
 362:  08 95         ret

00000364 <main>:
#include "RX5808.h"

// declar


int main(void) {
 364:  cf 93         push  r28
 366:  df 93         push  r29
 368:  1f 92         push  r1
 36a:  cd b7         in  r28, 0x3d  ; 61
 36c:  de b7         in  r29, 0x3e  ; 62
    RX5808 rx;
 36e:  ce 01         movw  r24, r28
 370:  01 96         adiw  r24, 0x01  ; 1
 372:  0e 94 40 00   call  0x80  ; 0x80 <_ZN6RX5808C1Ev>
    rx.setFrequency(0);
 376:  60 e0         ldi  r22, 0x00  ; 0
 378:  70 e0         ldi  r23, 0x00  ; 0
 37a:  ce 01         movw  r24, r28
 37c:  01 96         adiw  r24, 0x01  ; 1
 37e:  0e 94 a4 00   call  0x148  ; 0x148 <_ZN6RX580812setFrequencyEj>
 382:  ff cf         rjmp  .-2        ; 0x382 <main+0x1e>

00000384 <_exit>:
 384:  f8 94         cli

00000386 <__stop_program>:
 386:  ff cf         rjmp  .-2        ; 0x386 <__stop_program>

Was hats eigentlich mit den UNDEFINED SYMBOLS in der .lst auf sich ->
_ZN6RX5808C1Ev
_ZN6RX580812setFrequencyEj

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> Stefan schrieb:
>> Aber es wäre besser als Makro ?
>> PORTD &= ~(1<<pinNr) ;
>
> der Compiler muss erkennen das PinNr eine Konstante ist, dann wird
> daraus ein SetBit oder ClearBit. Wenn er das nicht erkennt dann wird das
> sehr umständlicher code.

Okay ich kann dir folgen, aber der Compiler sollte ja auch erkennen dass 
es eine konstante ist da sie über #define deklariert wird oder nicht ?

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> code nach der Optimierung ?

nein, das ist überhaupt nichts optimiert.

Da ist der oben angesprochen umständliche code mit schleife. Bei einer 
guten Optimierung, dürfte das nur 1 Zeile sein.
  86:  44 23         and  r20, r20
  88:  49 f0         breq  .+18       ; 0x9c <_ZN6RX58086setPINEhh+0x16>
        PORTD = 1<<pinNr ;
  8a:  81 e0         ldi  r24, 0x01  ; 1
  8c:  90 e0         ldi  r25, 0x00  ; 0
  8e:  06 2e         mov  r0, r22
  90:  01 c0         rjmp  .+2        ; 0x94 <_ZN6RX58086setPINEhh+0xe>
  92:  88 0f         add  r24, r24
  94:  0a 94         dec  r0
  96:  ea f7         brpl  .-6        ; 0x92 <_ZN6RX58086setPINEhh+0xc>
  98:  8b b9         out  0x0b, r24  ; 11
  9a:  08 95         ret
    }else{
        PORTD = 0<<pinNr ;
  9c:  1b b8         out  0x0b, r1  ; 11
  9e:  08 95         ret

000000a0 <_ZN6RX58085spi_1Ev>:
  a0:  1b b8         out  0x0b, r1  ; 11
  #else
    //round up by default
    __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
  #endif

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> Carl D. schrieb:
>> Stefan schrieb:
>> Beim C-Lernen auf einem AVR macht es Sinn sich die .lss-Datei
>> anzuschauen. Da ist man doch (anfangs) überrascht, was der Compiler so
>> produziert. Wenige können es (über alles betrachtet) besser und keiner
>> von denen auch nur annähernd so schnell. Und viele Gerüchte erkennt man
>> als solche.
>
> Gut ich hab mir die .lss jetzt mal angesehen und ehrlich gesagt auch das
> erste mal für mich sieht das jetzt aus wie der tatsächliche Assembler
> code nach der Optimierung ?
>

Das sieht eher so aus, als würde der Optimizer noch darauf warten 
eingeschaltet zu werden.
Allein daß der Konstruktor für rx, der aus 2 Befehlen besteht, nicht 
inlined wird, zeigt das.
Wie wurde der AVR-GCC gerufen und welche Version ist es. Option -v macht 
ihn gesprächig.

Autor: Carl Drexler (jcw2)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, jetzt hab ich dem GCC mal die Chance gegeben, sich zu 
rehabilitieren.
AVR-GCC 6.2 mit Optimierung -Os, was Size bedeutet'und weshalb die 
diversen Pinwackler nicht inlined werden.
Gebraucht hat er dafür 410ms. Nur so als zeitlich Vorgabe für "Freund" 
Moby, falls der das besser machen will. Ich kann notfalls auch auf das 
Milli verzichten ;-)

Autor: tictactoe (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Stefan schrieb:
> PORTD != (1<<pinNr) ;

Sollte doch wohl eher
PORTD |= (1<<pinNr) ;
sein.

Peter II schrieb:
> der Compiler muss erkennen das PinNr eine Konstante ist, dann wird
> daraus ein SetBit oder ClearBit. Wenn er das nicht erkennt dann wird das
> sehr umständlicher code.

Um das zu garantieren, würde ich die Funktion als Template schreiben:
template<uint8_t pinNr>
void setPIN(uint8_t state) {
    if (state) {
        PORTD |= 1<<pinNr;
    }else{
        PORTD &= ~(1<<pinNr);
    }
}
Benutzt wird die Funktion dann so:
setPIN<SPI_CLOCK_PIN>(LOW);
Der Vorteil ist, dass man dann nur mehr Aufrufe hinschreiben kann, die 
der Compiler auch wirklich optimieren kann.

Ich persönlich würde auch noch auf den state Parameter verzichten und 
zwei Funktionen machen: setPIN und clearPIN.

Autor: René H. (Firma: Herr) (hb9frh)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
tictactoe schrieb:
> Um das zu garantieren, würde ich die Funktion als Template schreiben:

Saubere Lösung!

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan schrieb:
> Der Code ist noch nicht getestet, stimmt natürlich das war Blödsinn
>
> void RX5808::setPIN( uint8_t pinNr, uint8_t state){
>     if (state) {
>         PORTD != (1<<pinNr) ;
>     }else{
>         PORTD &= ~(1<<pinNr) ;
>     }
> }

Das auch. Was willst Du mit dem Ausrufezeichen da?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Stefan schrieb:
>> Der Code ist noch nicht getestet, stimmt natürlich das war Blödsinn
>>
>> void RX5808::setPIN( uint8_t pinNr, uint8_t state){
>>     if (state) {
>>         PORTD != (1<<pinNr) ;
>>     }else{
>>         PORTD &= ~(1<<pinNr) ;
>>     }
>> }
>
> Das auch. Was willst Du mit dem Ausrufezeichen da?

Nichts besonderes, es sollte nur einleuten einfach mal schlafen zu 
gehen.
Ich bin gerade in der Arbeit, und hab das Makefile nicht mit. Ich denke 
es ist ein "s" eingetragen.

Autor: Mich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Stefan schrieb:
>> Carl D. schrieb:
>>> Stefan schrieb:
> Das sieht eher so aus, als würde der Optimizer noch darauf warten
> eingeschaltet zu werden.
> Allein daß der Konstruktor für rx, der aus 2 Befehlen besteht, nicht
> inlined wird, zeigt das.
> Wie wurde der AVR-GCC gerufen und welche Version ist es. Option -v macht
> ihn gesprächig.

Hier gleich mal ein kleiner Auszug mit allen Infos

"
# Optimization level, can be [0, 1, 2, 3, s].
#     0 = turn off optimization. s = optimize for size.
#     (Note: 3 is not always the best optimization level. See avr-libc 
FAQ.)
OPT = s


# Debugging format.
#     Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
#     AVR Studio 4.10 requires dwarf-2.
#     AVR [Extended] COFF format requires stabs, plus an avr-objcopy 
run.
DEBUG = stabs


# List any extra directories to look for include files here.
#     Each directory must be seperated by a space.
#     Use forward slashes for directory separators.
#     For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = src


# Compiler flag to set the C Standard level.
#     c89   = "ANSI" C
#     gnu89 = c89 plus GCC extensions
#     c99   = ISO C99 standard (not yet fully implemented)
#     gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu++03


# Place -D or -U options here
CDEFS = -DF_CPU=$(F_CPU)UL


# Place -I options here
CINCS =



#---------------- Compiler Options ----------------
#  -g*:          generate debugging information
#  -O*:          optimization level
#  -f...:        tuning, see GCC manual and avr-libc documentation
#  -Wall...:     warning level
#  -Wa,...:      tell GCC to pass this to the assembler.
#    -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS) $(CINCS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct 
-fshort-enums
CFLAGS += -Wall -Wstrict-prototypes
CFLAGS += -Wa,-adhlns=$(addprefix $(OBJDIR)/,$(<:.cpp=.lst))
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
CFLAGS += -gstabs
CFLAGS += -gstrict-dwarf
"
Avr-gcc ist in der version 4.8.3

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da hat GCC aber erheblich dazugelernt, denn der 6.2 (aber auch 5.3) hat 
kein Probleme Konstanten über mehrere Call-Level hinweg als solche zu 
erkennen.
Das fehlt in dem 4.8er .lss völlig. Die Bitmaske für den (eigentlich 
unnötigen) Byte-Zugriff auf die Ports wird zur Laufzeit berechnet. Wenn 
ein AVR etwas nich mag, dann daß.
Beim 6.2er Binary sind ab 0x74/0xa4 die Routinen für Bit-Ausgabe an SPI 
zu finden. Überall SBI/CBI. Nur das delay_us(1) macht eine Schleife, 
alternativ wären da 16 NOPs, aber Wir optimieren ja "auf Größe" und als 
Schleife sind es nur 4 Befehle. Wenn man da noch drunter kommen will, 
dann braucht man eine eigene Funktion für "Delay 1μs", deren Aufruf 
braucht nur 2 Byte. Die muß man aber vor LTO retten.
Ich hatte verschieden Varianten des Programms ausprobiert, mit/ohne 
Templates, wie oben vorgeschlagen, und noch ein Paar Änderungen. Mit 
frustrierendem Ergebnis: immer das gleiche Binary. Man muß dem Compiler 
also nur sagen, was er machen soll, das Wie kann er selber.

Autor: c-hater (Gast)
Datum:

Bewertung
-5 lesenswert
nicht lesenswert
Bernd K. schrieb:

> Seitdem hab ich keine Skrupel mehr zum Beispiel sowas zu schreiben:
[...]

> Das alles schrumpft durch LTO zusammen auf zwei ASM-Instruktionen im IRQ

Siehste, und genau deswegen schreibe ich für kleine µC gleich in Asm. 
Warum sollte man auch das ganze, offensichtlich völlig redundante 
Syntaxgelalle von C oder gar C++ hinschreiben, wenn man die gleiche 
Funktionalität mit zwei simplen Zeilen Asm erreichen kann? Das ist doch 
extrem widersinnig! Der Plan bei Hochsprachen war doch eigentlich, 
Programmcode schneller und fehlerfreier schreiben zu können...

Dieses Ziel wurde ganz offensichlich megamäßig verfehlt...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:

ad LTO

> Nur sollte man einen einigermaßen aktuellen Compiler haben (meiner nennt
> sich gerade 6.2, also nicht "sehr alt") und Compiler und Linker müssen
> mit "-Os -flto" gefüttert werden. Beide! Und mit der gleichen
> Optimierungsstufe.

Ab GCC 5 gilt für LTO:
Command-line optimization and target options are now streamed on a
per-function basis and honored by the link-time optimizer. [...]
Contrary to earlier GCC releases, the optimization and target options passed on the link command line are ignored.

Note that this applies only to those command-line options that can be
passed to optimize and target attributes. Command-line options affecting
global code generation, warnings, optimizations affecting the way static
variables are optimized, debug output, and --param parameters can be
applied only to the whole link-time optimization unit.

http://gcc.gnu.org/gcc-5/changes.html

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Carl D. schrieb:
>
> ad LTO
>
>> Nur sollte man einen einigermaßen aktuellen Compiler haben (meiner nennt
>> sich gerade 6.2, also nicht "sehr alt") und Compiler und Linker müssen
>> mit "-Os -flto" gefüttert werden. Beide! Und mit der gleichen
>> Optimierungsstufe.
>
> Ab GCC 5 gilt für LTO:
>
>
> Command-line optimization and target options are now streamed on a
> per-function basis and honored by the link-time optimizer. [...]
> Contrary to earlier GCC releases, the optimization and target options 
> passed on the link command line are ignored.
> 
> Note that this applies only to those command-line options that can be
> passed to optimize and target attributes. Command-line options affecting
> global code generation, warnings, optimizations affecting the way static
> variables are optimized, debug output, and --param parameters can be
> applied only to the whole link-time optimization unit.
>
> http://gcc.gnu.org/gcc-5/changes.html

Danke Johann für diesen Hinweis. Das muß ich mir dann irgendwie zu 
4.9-Zeiten gemerkt haben.

Und wenn ich dich schon da hab, vielen Dank für die phantastische Arbeit 
am GCC AVR-Backend.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
3 lesenswert
nicht lesenswert
c-hater schrieb:
> Warum sollte man auch das ganze, offensichtlich völlig redundante
> Syntaxgelalle von C oder gar C++ hinschreiben, wenn man die gleiche
> Funktionalität mit zwei simplen Zeilen Asm erreichen kann?

Machst Du jetzt den Moby?

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
4 lesenswert
nicht lesenswert
c-hater schrieb:
> Der Plan bei Hochsprachen war doch eigentlich,
> Programmcode schneller und fehlerfreier schreiben zu können...

Und genau das wird hier erreicht. Ich kann so viele 
Abstraktionsschichten einziehen wie ich der Modularität, Entkopplung, 
Wiederverwendbarkeit und Übersicht zuliebe für sinnvoll erachte und der 
Compiler macht trotzdem weitaus effizienteren Code draus als Du oder 
Moby oder ich oder sonstwer es jemals in akzeptabler Zeit zu Fuß 
erreichen könnten und ohne daß sich dann irgendeine arme Seele immer und 
immer wieder durch zigtausend Zeilen undurchdringliches 
ASM-Spaghetti-Gestrüpp durchschlagen müsste für jede popelige Änderung 
oder Erweiterung oder gar Wiederverwendung.

Autor: M.Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Und genau das wird hier erreicht. Ich kann so viele
> Abstraktionsschichten einziehen wie ich der Modularität, Entkopplung,
> Wiederverwendbarkeit und Übersicht zuliebe für sinnvoll erachte und der
> Compiler macht trotzdem weitaus effizienteren Code draus als Du oder
> Moby oder ich oder sonstwer es jemals in akzeptabler Zeit zu Fuß
> erreichen könnten und ohne daß sich dann irgendeine arme Seele immer und
> immer wieder durch zigtausend Zeilen undurchdringliches
> ASM-Spaghetti-Gestrüpp durchschlagen müsste für jede popelige Änderung
> oder Erweiterung oder gar Wiederverwendung.

Offensichtlich kannst Du mit C++ gut umgehen und für Dich und Deine 
Anwendungen einen Vorteil daraus ziehen. Das sei Dir von Herzen gegönnt. 
Deine Darstellung krankt aber ganz erheblich an ihrer absolutgültigen 
Aussage, weil sie Art der Anwendung, Fähigkeiten des Programmierers und 
die konkreten Anforderungen aus dem Betriebsalltag völlig außen vor 
lässt.

Autor: Oliver S. (oliverso)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Modularität, Entkopplung,
> Wiederverwendbarkeit und Übersicht

M.Peter schrieb:
> krankt aber ganz erheblich an ihrer absolutgültigen
> Aussage, weil sie Art der Anwendung, Fähigkeiten des Programmierers und
> die konkreten Anforderungen aus dem Betriebsalltag völlig außen vor
> lässt.

Ganz ehrlich, wer sein Geld mit professioneller Softwareerstellung 
verdient, der sollte das auch können. Und da kann es gar nicht so viel 
"Betriebsalltag" geben, als daß die grundlegendsten Anforderungen außer 
acht gelassen werden sollten.

Viele Wege führen nach Rom, und C++ ist nur einer davon.

Unkoordiniertes draufloshacken ist allerdings grundsätzlich für keine 
Anwendung eine Option.

Oliver

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich bislang vermisse ist ein praktikabler Ersatz für __flash, 
zumindest für avr-g++.  Für C gibt's __flash zwar nur als C-Erweiterung, 
allerdings scheint es ganz gut akzeptiert zu werden.

Zwar werden immer wieder Buzzwords wie "Smart Pointer" genannt, aber 
eine allgemein akzeptierte und verbreitete Lösung scheint es nicht zu 
geben.

Ein Problem bei C++ ist auch, das im Gegensatz zu C ein const Objekt zur 
Laufzeit geändert werden kann, etwa wenn die Konstruktion eines 
statischen Konstruktors bedarf.

Falls jemand eine zufriedenstellende Implementierung in C++ hat, kann 
man davon bestimmt einiges lernen :-)

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Was ich bislang vermisse ist ein praktikabler Ersatz für __flash,
> zumindest für avr-g++.  Für C gibt's __flash zwar nur als C-Erweiterung,
> allerdings scheint es ganz gut akzeptiert zu werden.
>
> Falls jemand eine zufriedenstellende Implementierung in C++ hat, kann
> man davon bestimmt einiges lernen :-)

Für einen nicht unwichtigen Teil des Flash-Problems, String-Konstanten, 
gibt es diesen Lösungsweg:

Beitrag "Interessante g++ Erweiterung für user-defined literals"

oder kurz: mit ca 20 Zeilen Code (und aktuell nur an ostream angebunden 
:-( ) ist folgendes möglich:
  os << "ein Text in Flash"_pgm;
wobei mehrfaches Auftreten des selben Strings zu nur einer Instanz im 
Flash führt.



PS: das ganze geht auch universeller. Gibt mir einen Tag, dann hab 
ich's.

: Bearbeitet durch Moderator

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.