Peak bei Initialisierung

#778007
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
Persönliche Seite #778015
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.
Persönliche Seite #778050
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
}
#778064
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
#778066
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?
Persönliche Seite #778102
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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren