Forum: Mikrocontroller und Digitale Elektronik AVR USART und SLEEP_MODE_PWR_DOWN


von Info (Gast)


Lesenswert?

Folgendes Programm für ATmega48pa @ 1.5 MHz schaltet den TXD im sleep 
mode power-down auf low:
1
#include <stdint.h>
2
#include <stdbool.h>
3
#include <avr/io.h>
4
#include <avr/wdt.h>
5
#include <avr/sleep.h>
6
#ifdef sleep_mode
7
#undef sleep_mode
8
#define sleep_mode()\
9
  cli();\
10
  MCUCR |= 1<<SE;\
11
  sei();\
12
  asm volatile("sleep");\
13
  cli();\
14
  MCUCR &= ~(1<<SE);\
15
  sei();
16
#endif
17
#include <avr/interrupt.h>
18
19
void uart_putchar( char c )
20
{
21
  while ( !( UCSR0A & (1<<UDRE0)) );
22
  UDR0 = c;
23
  return;
24
}
25
26
int main(void)
27
{
28
  wdt_disable();
29
  ACSR = (1<<ACD);
30
  MCUCR |= (1<<BODS);
31
  
32
  #define BAUD 9600UL      // Baudrate
33
  #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
34
  #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
35
  #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
36
  #if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
37
    #warning Fehler der Baudrate ist groesser als 1% ! 
38
  #endif
39
  UBRR0  = UBRR_VAL;
40
  UCSR0B = (1<<TXEN0);
41
  UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
42
  
43
  uart_putchar( 'H' );
44
  uart_putchar( 'E' );
45
  uart_putchar( 'L' );
46
  uart_putchar( 'L' );
47
  uart_putchar( 'O' );
48
  uart_putchar( '\n' );
49
50
  TCNT1  = 0;
51
  OCR1A  = 2047;
52
  OCR1B  = 0;
53
  TCCR1A = 0;
54
  TCCR1B = (1<<CS12)| (1<<CS10);
55
  TIMSK1 = (1<<OCIE1A);
56
  
57
  set_sleep_mode(SLEEP_MODE_IDLE);
58
  sei();
59
  while(1)
60
  {
61
    uart_putchar( 'S' );
62
    
63
    //sleep_mode();
64
    cli();
65
    sleep_enable();
66
    sei();
67
    
68
    sleep_cpu();
69
    
70
    cli();
71
    sleep_disable();
72
    sei();
73
    
74
    uart_putchar( 'W' );
75
  }
76
}
77
78
ISR( TIMER1_COMPA_vect ) 
79
{
80
  uart_putchar( 'T' );
81
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
82
}

Was dazu führt, dass die Gegenseite eine 0 empfängt:
1
HELLO<\n>
2
ST<\0>


Wenn man den USART nach Initialisierung gleich wieder mit PRR = 
(1<<PRUSART0); abschaltet, passiert dies auch:
1
HELL<\0>

In der Doku finde ich nur folgendes:
> The Transmitter will override normal port operation for the TxDn pin when 
enabled.
> When disabled, the Transmitter will no longer override the TxDn pin.

Also selbst, wenn, wie im letzten Fall, der USART mitten in der 
Übertragung abgeschaltet wird, sollte der Pin doch eigentlich wieder zum 
Eingang (high-Z) werden!?


Auch das Deaktivieren ändert daran nichts:
1
  ...
2
  UBRR0  = UBRR_VAL;
3
  UCSR0B = (1<<TXEN0);
4
  UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
5
  uart_putchar( 'H' );
6
  PRR = (1<<PRUSART0);
7
  UCSR0B = 0;
8
  while(1);


Auch das Warten auf Übertragungsende mit while ( !( UCSR0A & (1<<UDRE0)) 
); ändert nichts.

Reihenfolge ändern (PRR nach UCSR0B) bringt auch nichts -> Power-Down 
und PRR schalten TX low!

Ausnahme offenbar: UCSR0B = 0; vor Power-down.

Soll das so sein, wo ist es dokumentiert?

von Info (Gast)


Lesenswert?

Hier ein Hinweis auf den TX Buffer:
http://www.avrfreaks.net/forum/uart-and-sleep-mode-not-working-well
1
void uart_putchar( char c )
2
{
3
  while ( !( UCSR0A & (1<<UDRE0)) );
4
  UDR0 = c;
5
  UCSR0A &= ~(1<<UDRE0);
6
  
7
  while ( !( UCSR0A & (1<<TXC0)) );
8
  UCSR0A |= (1<<TXC0);
9
  
10
  return;
11
}

umgeht das Problem.

Info schrieb:
> Ausnahme offenbar: UCSR0B = 0; vor Power-down.

Evtl. durch die entstehende Verzögerung?

von Info (Gast)


Lesenswert?

UDREn muss wohl nicht gelöscht werden?

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.