Sleep Modus und falsche UART Sendungen

OP #2488365
Lesenswert?

Hi,

ich möchte ein Byte über UART im Atmega169 pro Sekunde senden lassen. 
Ein 32.768kHz Quarz wird für Timer2 eingesetzt und der interne RC 
Oszillator wird als Systemtakt verwendet.

Das Problem ist, wenn der 169 aus dem Schlafmodus „Power Save“ erweckt 
wird, sendet dieser falsche Bytes. Ohne Schlafmodus ist alles OK.

Zu bemerken: In diesen falschen Bytes gibt es sogar Regel: Das richtige 
Byte 0x5A wird alle 25 Bytes gesendet, dazwischen nur 0x00 und 0xEB, 
also
5A 00 EB 00 EB 00 EB 00 EB 00 EB 00 EB 00 EB 00 EB 00 EB 00 EB 00 EB 00 
EB 5A

Ich vermute mal, dass der Systemtakt von 1MHz nach dem Schlafmodus 
verstellt ist, aber wieso? Inzwischen habe ich auch versucht, alle 
Initialisierungen nach jedem Schlafmodus neu zu machen, erfolgslos!

Der Code ist hier:
1
int main( void )
2
{
3
  clock_init_1MHz();
4
  
5
  RTC_init();
6
  USART_Init(12); // 9600bps bei 1MHz
7
 
8
  __enable_interrupt();
9
  
10
  for(;;)
11
  { 
12
    Delay(1000);    // wait for 1 sec to let the Xtal stabilize after a power-on
13
    Usart_Tx(0x5A);
14
    while(!(UCSR0A & (1<<TXC0)));
15
    
16
    SMCR = (3<<SM0) | (1<<SE);      // Enable Power-save mode
17
    __sleep();                      // Go to sleep
18
                
19
    SMCR = 0;                       // Just woke, disable sleep
20
  }
21
}
22

23
void clock_init_1MHz(void)
24
{
25
  CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
26
    
27
  // set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
28
  CLKPR = (1<<CLKPS1) | (1<<CLKPS0); 
29
}
30

31
void Delay(unsigned int millisec)
32
{
33
    int i;
34
    
35
    while (millisec--)
36
        for (i=0; i<125; i++);
37
}
38

39
void RTC_init(void)
40
{
41
    Delay(1000);            // wait for 1 sec to let the Xtal stabilize after a power-on,
42

43
    __disable_interrupt();  // disabel global interrupt
44

45
    cbi(TIMSK2, TOIE2);             // disable OCIE2A and TOIE2
46

47
    ASSR = (1<<AS2);        // select asynchronous operation of Timer2
48

49
    TCNT2 = 0;              // clear TCNT2A
50
    TCCR2A |= (1<<CS22) | (1<<CS20);             // select precaler: 32.768 kHz / 128 = 1 sec between each overflow
51
    
52
    while((ASSR & (0x01 | 0x04)));       // wait for TCN2UB and TCR2UB to be cleared
53

54
    TIFR2 = 0xFF;           // clear interrupt-flags
55
    sbi(TIMSK2, TOIE2);     // enable Timer2 overflow interrupt
56

57
    OCR2A = 200;    // set timer2 compare value
58
    
59
    __enable_interrupt();                 // enable global interrupt
60
}
61

62
#pragma vector = TIMER2_OVF_vect
63
__interrupt void TIMER2_OVF_interrupt(void)
64
{
65
}
66

67
void USART_Init(unsigned int baudrate)
68
{
69
    // Set baud rate
70
    UBRR0H = (unsigned char)(baudrate>>8);
71
    UBRR0L = (unsigned char)baudrate;
72

73
    // Enable 2x speed
74
    UCSR0A = (1<<U2X0);
75

76
    // Enable receiver and transmitter
77
    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(0<<RXCIE0)|(0<<UDRIE0);
78

79
    // Async. mode, 8N1
80
    UCSR0C = (0<<UMSEL0)|(0<<UPM00)|(0<<USBS0)|(3<<UCSZ00)|(0<<UCPOL0);
81
}
82

83
void Usart_Tx(char data)
84
{
85
    while (!(UCSR0A & (1<<UDRE0)));
86
    UDR0 = data;
87
}

Hat jemand Ideen?

Gruss
Owen
#2488368
Lesenswert?

Woher beziehst du denTakt für UART? Ist der RC-Oszillator abgeglichen? 
Für UART sollte man Quarze verwenden, da der RC temperaturabhängig ist. 
Vielleicht muss nach dem Aufwachen erst noch alles sauber einschwingen, 
obwohl RCs da in der Regel die schnellsten sind. Trotzdem würde ich mal 
beim Takt anfangen zu suchen und mit einem schnellen Quarz testen.
Gast #2488413
Lesenswert?

> Das Problem ist, wenn der 169 aus dem Schlafmodus „Power Save“ erweckt
> wird, sendet dieser falsche Bytes. Ohne Schlafmodus ist alles OK.

In den Sparmodi unterhalb von "IDLE" sind die UARTs nicht mehr 
verfügbar, siehe: Sleep Mode.

Die "komischen" Zeichen enstehen, weil dem UART mitten im Byte die 
Taktquelle verloren geht und er dann einfach seinen Pegel hält. Da die 
Übertragung asynchron ist, erhält der PC dann verwürfelte Daten.

Abhilfe: Tiefere Stromspar-Modi nur verwenden, wenn nichts über UART 
gesendet oder empfangen werden muss.
OP #2492453
Lesenswert?

Vielen Dank für Deine Abhilfe.

Das funktioniert wirklich wenn der "Idle" Modus gewählt wird. Trotzdem 
verstehe ich dies nicht. In meinem Beispielcode geht der Controller in 
den "Power Save" Modus nachdem das Byte bereits fertiggeschickt wird. 
Warum wird die Taktquelle verloren?

Gruss
Owen
#2492699
Lesenswert?

Turbo J schrieb:
> Die "komischen" Zeichen enstehen, weil dem UART mitten im Byte die
> Taktquelle verloren geht und er dann einfach seinen Pegel hält. Da die
> Übertragung asynchron ist, erhält der PC dann verwürfelte Daten.

Wenn das so ist, dann ist nur das letzte (abgebrochene) Zeichen falsch. 
Dann ist Ruhe, da ja keine neuen Startzeichen kommen.

Die Ursache muss also eine andere sein.

Gruß Dietrich

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