Forum: Compiler & IDEs Peak bei Initialisierung


von Norbert S. (norton)


Lesenswert?

Hallo, ich habe folgendes Problem:

Ich habe eine LED am PORTB PB0 welche wenn der Ausgang gesetzt ist NICHT 
leuchtet.
Bei meinem Programm wird anfangs der Watchdog gesetzt anschließend 
werden die Ports gesetzt und dann der Prozessor abgeschaltet.
1
int main( void )
2
{
3
  wdt_enable(WDTO_120MS);          //Watchdog akivieren
4
  clock_prescale_set(clock_div_2);
5
  DDRB  = 0b00010111;
6
  PORTB  = 0b11101101;
7
8
  sleep_mode();

Das Problem ist, dass beim initialisieren des Portes immer ein Peak 
entsteht, der wenn man das selbe in Assembler schreibt, bei der ASM 
Variante "ASM noPeak" nicht entsteht.

//ASM noPeak
/*
     ldi   TEMP    , 0b00010111
     ldi   _TEMP   , 0b11101101
     out   PORTB   , _TEMP
     out   DDRB    , TEMP                ; Port B initialisieren
*/

//ASM Peak
/*
         ldi       TEMP    , 0b00010111
         out       DDRB    , TEMP                ; Port B initialisieren
         ldi       _TEMP   , 0b11101101
         out       PORTB   , _TEMP
*/

Gibt es eine Möglichkeit das Port in C so zu intialisieren ,dass dieser 
Peak ebenfalls nicht entsteht?

Danke Norton

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wenn es nur die Reihenfolge der Portzugriffe (1. PORTB setzen, 2. DDRB 
setzen statt 1. DDRB und 2. PORTB) ist, dann so:
1
   
2
     // ASM No-Peak
3
     // ldi   TEMP    , 0b00010111
4
     // ldi   _TEMP   , 0b11101101
5
     // out   PORTB   , _TEMP
6
     // out   DDRB    , TEMP
7
     PORTB = 0xED;
8
     DDRB = 0x17;

Wenn du die zwei OUT Befehle unmittelbar hintereinander brauchst, melde 
dich noch mal.

von Norbert S. (norton)


Lesenswert?

Ja genau um die zwei OUT befehle geht es. Gibts da auch eine elegante 
Lösung die gleich hintereinander zu machen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Fällt mir ausser über Inline-Assembler nur der Umweg über eine Funktion 
ein.
1
#include <avr/io.h>
2
3
void doit(unsigned char t1, unsigned char t2) __attribute__ ((noinline));
4
5
void doit(unsigned char t1, unsigned char t2)
6
{
7
  PORTB = t1;
8
  DDRB = t2;
9
}
10
11
int main(void)
12
{
13
  doit(0xED, 0x17);
14
15
  while(1)
16
    ;
17
18
  return 0;
19
}

von Peter D. (peda)


Lesenswert?

Norbert S. wrote:
> Gibt es eine Möglichkeit das Port in C so zu intialisieren ,dass dieser
> Peak ebenfalls nicht entsteht?

Natürlich, schreibs einfach in der richtigen Reihenfolge hin.

Der Peak entsteht dadurch, daß Du erst den Pin auf Ausgang setzt und 
später auf High.

Machs umgekehrt und der Peak ist weg.



> Ja genau um die zwei OUT befehle geht es. Gibts da auch eine elegante
> Lösung die gleich hintereinander zu machen.

Dazu gibts keinen Grund, die zusätzlichen 50ns merkt keine Sau nach den 
65000000ns Resetzeit.


Peter

von Norbert S. (norton)


Lesenswert?

Danke für die Antwort @stefan

Die Funktion hat leider nicht den gewünschte Erfog gebracht.
Ich bin noch Anfäger und hätte da noch einige dumme Fragen:

> void doit(unsigned char t1, unsigned char t2) __attribute__
> ((noinline));

Was bewirkt diese Zeile eigentlich?


Habe mich mal mit Inline Assembler versucht und bekomme folgenden 
Fehler:
1
asm volatile ("ldi   r16     , 0b00010111    \n\t"
2
              "ldi   r17     , 0b11101101    \n\t"
3
              "out   PORTB   , r17           \n\t"
4
              "out   DDRB    , r16        \n\t"
5
        );
C:\DOKUME~1\NORBER~1\LOKALE~1\Temp/ccBMwlIL.s:75: Error: constant value 
required

Was ist bei der Inline Assembler Funktion falsch?

von Norbert S. (norton)


Lesenswert?

Danke an alle!

Ich habe nun zuerst den Pin gesetzt und anschließend auf Ausgang --> der 
Peak ist weg.
(so einfach kann die Lösung sein :-) )

Aus interesse würde trotzdem gerne wissen was beim Inline Assembler 
schief gelaufen ist?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Und ich frage extra noch, ob es nur um die Reihenfolge geht ;-)

Zu Inline_Assembler gibt es eine gute Doku bei 
http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
1
#include <avr/io.h>
2
3
void doit(unsigned char t1, unsigned char t2) __attribute__ ((noinline));
4
5
void doit(unsigned char t1, unsigned char t2)
6
{
7
  PORTB = t1;
8
  DDRB = t2;
9
}
10
11
int main(void)
12
{
13
  // doit(0xED, 0x17);
14
15
  asm volatile ("ldi   r17, %0    \n\t"
16
                "ldi   r16, %1    \n\t"
17
                "out   %2, r17    \n\t"
18
                "out   %3, r16    \n\t"
19
                // Ausgabe (leer)
20
                :
21
                // Eingabe
22
                : "M" (0xED), "M" (0x17),  
23
                  "I" (_SFR_IO_ADDR(PORTB)), "I" (_SFR_IO_ADDR(DDRB))
24
                // verschmutzt
25
                : "r17", "r16"                                           
26
        );
27
28
29
  while(1)
30
    ;
31
32
  return 0;
33
}

Diese Zeile
1
void doit(unsigned char t1, unsigned char t2) __attribute__ ((noinline));

verhindert, dass GCC die Pippifax-Funktion doit() inline in main() 
reinzieht. Als inline-Funktion würden die beiden OUT-Statements nicht 
unmittelbar hintereinander stehen. Der Code wäre inline identisch mit 
diesen Statements.
1
  PORTB = 0xED;
2
  DDRB = 0x17;

Möglicherweise funktioniert das bei in meinem Testfall nur wegen -Os 
Optimierung und/oder WinAVR-20071221 Version. Müsste man mehr 
experimenteren und jeweils das *.LSS File ansehen, was rauskommt.

Aber wenn deine Lösung jetzt ja funktioniert...

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.