Forum: Mikrocontroller und Digitale Elektronik AVR Atmega328P Fast PWM beeinflusst UART


von Lukas B. (lmwb)


Lesenswert?

Hallo Forum,

in einem Projekt verwende ich einen Atmega328P (classic Arduino Due 
Board aber mit Atmel ICE geflashed). Ich habe eine Fast PWM 
initialisiert (Timer0 Mode 3) und die UART Schnittstelle. Beide separat 
funktionieren super, aber sobald ich die PWM einschalte (Clock Source in 
TCCR0B Register) spinnt die UART komplett. Character werden nicht mehr 
korrekt übertragen oder empfangen. Es scheint als würde die BAUD Rate 
durch den Timer beeinflusst. Unten mein Code. Das meiste stammt aus 
einer Aplication Note. Hat jemand so was ähnliches schon mal erlebt?
1
#define F_CPU 16000000
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
6
#define BAUD 9600
7
#define MYUBRR F_CPU/16/BAUD-1
8
9
unsigned char UART_receive( void );
10
void UART_send( char data);
11
12
void AVR_init(void) {
13
14
    /* Clock init done by FUSES, CLK = 16 MHz ext. Oscillator */
15
    
16
    /*LED PIN*/
17
    /*---------------------------------------------------------*/
18
    DDRB = (1 << PINB5);
19
20
    /* init UART asynchronous 9600 8Bits 1Stop */
21
    /*---------------------------------------------------------*/
22
    /*Set baud rate registers according to MYUBRR definition*/
23
    UBRR0H = (unsigned char) (MYUBRR >> 8);
24
    UBRR0L = MYUBRR;
25
26
    /* Enable receiver and transmitter */
27
    UCSR0B = (1 << RXEN0) | (1 << TXEN0);
28
29
    /* Set frame format: 8data, 1stop bit */
30
    UCSR0C = (0 << UMSEL00);
31
    UCSR0C |= (0 << UCSZ00) | (1 << UCSZ01) | (1 << UCSZ00);
32
33
    /*init PWM, Timer*/
34
    /*---------------------------------------------------------*/
35
    /*Timer/Counte0 as PWM Waveform Generator on PD6/PD5 OC0A/OC0B (Arduino Pin 6, 5) (FAST PWM MODE 3)*/
36
    DDRD = (1 << PIND6);
37
    DDRD = (1 << PIND5);
38
    
39
    TCCR0A = (1 << COM0A1) | (0 << COM0A0);
40
    TCCR0A |= (1 << COM0B1) | (0 << COM0B0);
41
    
42
    /*MODE 3: Fast PWM TOPP = 0xFF*/
43
    TCCR0A |= (1 << WGM01) | (1 << WGM00);
44
    
45
    /* MODE 7 */
46
    TCCR0B |= (0 << WGM02);
47
    
48
    /*Select CLK Source and Prescaler*/
49
    /*Prescaler 1, 8, 64, 256, 1024*/
50
    TCCR0B |= (0 << CS02) | (1 << CS01) | (0 << CS00);
51
    // HIER GEHT WAS SCHIEF sobald ein CS0x bit gesetzt wird
52
    
53
    /*Interrupt enable*/
54
    TIMSK0 = (1 << OCIE0A) | (1 << OCIE0B);
55
    
56
    /*This Register defines compare Match => Duty Cycle PWM Channel A in MODE 3 activated*/
57
    /*This Register defines compare Match => Periode PWM Channel A in MODE 7 activated*/
58
    OCR0A = 128;
59
    
60
    /*This Register defines compare Match => Duty Cycle PWM Channel B in MODE 3 activated*/
61
    /*This Register defines compare Match => Duty Cycle PWM Channel A in MODE 7 activated*/
62
    OCR0B = 64;
63
    
64
    /* MODE3: Output Waveform Frequency = F_CPU/Prescaler/256  */
65
    /* MODE7: Output Waveform Frequency = F_CPU/2/Prescaler/(OCR0A+1)  */
66
    
67
    sei();
68
};
69
70
int main(void){
71
    
72
    AVR_init();
73
    
74
    while( 1 ) {
75
        UART_send( UART_receive() );
76
    }
77
}
78
79
unsigned char UART_receive(void){
80
    /* Wait for data to be received */
81
    while (!(UCSR0A & (1<<RXC0)));
82
    /* Get and return received data from buffer */
83
    return UDR0;
84
};
85
86
void UART_send( char data){
87
    /* Wait for empty transmit buffer */
88
    while (!(UCSR0A & (1<<UDRE0)));
89
    /* Put data into buffer, sends the data */
90
    UDR0 = data;
91
};

Hinweis: ich weiß, dass der Syntax
1
REG |= (0<<XXX);
 keine keine Resultat erzielt, ich nutzte es als Platzhalter / 
Vollständigkeit

viele Grüße und schon mal vielen Dank für Eure Anregungen
Lukas

von OMG (Gast)


Lesenswert?

Lukas B. schrieb:
> verwende ich einen Atmega328P (classic Arduino Due Board

Du musst dich schon entscheiden: Arduino Due oder Mega328P,
beides auf einem Board wirds wohl nicht sein.

von leo (Gast)


Lesenswert?

Lukas B. schrieb im Beitrag #6004981
> #define MYUBRR F_CPU/16/BAUD-1

Du solltest die rechte Seite von defines immer klammern, denn ...

>     UBRR0H = (unsigned char) (MYUBRR >> 8);

bei sowas kann Unerwartetes entstehen, naemlich ...
1
  F_CPU/16/BAUD - 1 >> 8

(Leerzeichen zecks Lesbarkeit)

leo

von Majestix (Gast)


Lesenswert?

Die klassische Einstiegsfrage: Blockkondensatoren 10nF/100nF hinreichend 
vorhanden? Am ATmega und am weiteren UART-Pfad (USB-Serial  max232  
...)?
Versorgungsspannung glatt?

von Lukas B. (lmwb)


Lesenswert?

OMG schrieb:
> Lukas B. schrieb:
>> verwende ich einen Atmega328P (classic Arduino Due Board
>
> Du musst dich schon entscheiden: Arduino Due oder Mega328P,
> beides auf einem Board wirds wohl nicht sein.

Arduino Duemilanove ist das Board, Atmega328P ist der Controller. Stimmt 
also beides ;)

von Hendrik (Gast)


Lesenswert?

Lukas B. schrieb:
> OMG schrieb:
>> Lukas B. schrieb:
>>> verwende ich einen Atmega328P (classic Arduino Due Board
>>
>> Du musst dich schon entscheiden: Arduino Due oder Mega328P,
>> beides auf einem Board wirds wohl nicht sein.
>
> Arduino Duemilanove ist das Board, Atmega328P ist der Controller. Stimmt
> also beides ;)

Dann musst Du ihn auch Duemilanove nennen, der Due hat einen SAM 
Prozessor drauf ;-)

von Thomas E. (thomase)


Lesenswert?

Lukas B. schrieb:
> TIMSK0 = (1 << OCIE0A) | (1 << OCIE0B);

Wo sind deine ISRs?

von Joachim B. (jar)


Lesenswert?

was denn nun SAM oder AVR?

von Lukas B. (lmwb)


Lesenswert?

Thomas E. schrieb:
> Lukas B. schrieb:
>> TIMSK0 = (1 << OCIE0A) | (1 << OCIE0B);
>
> Wo sind deine ISRs?

ISR braucht man nicht bei Fast PWM, die Pins werden direkt vom 
CombarMatch geschalten. Nix Software, alles autarke Hardware.
1
 
2
TCCR0A = (1 << COM0A1) | (0 << COM0A0);
3
TCCR0A |= (1 << COM0B1) | (0 << COM0B0);
4
    
5
TCCR0A |= (1 << WGM01) | (1 << WGM00);

Zitat Datacheet: Clear OC0A on compare match, set OC0A at BOTTOM,
(non-inverting mode).

von Lukas B. (lmwb)


Lesenswert?

Joachim B. schrieb:
> was denn nun SAM oder AVR?

AVR Atmega328P-PU, also im DIP-28 Package.
Sorry für die Verwirrung;)

von Thomas E. (thomase)


Lesenswert?

Lukas B. schrieb:
> ISR braucht man nicht bei Fast PWM, die Pins werden direkt vom
> CombarMatch geschalten. Nix Software, alles autarke Hardware.

Wenn du meinst. Ich wünsche dir dann noch viel Spass mit deiner weiteren 
Bastelei.

von Wolfgang (Gast)


Lesenswert?

Lukas B. schrieb:
> Arduino Duemilanove ist das Board, Atmega328P ist der Controller. Stimmt
> also beides ;)

Ein Arduino Duemilanove ist kein Arduino Due.

Auf dem Arduino Due sitzt ein SAM3X8E ARM Cortex-M3 Controller.
https://www.arduino.cc/en/Guide/ArduinoDue

von S. Landolt (Gast)


Lesenswert?

> ISR braucht man nicht bei Fast PWM

Korrekt. Nur - weshalb werden die Interrupts dann freigegeben?


> /*Interrupt enable*/
>    TIMSK0 = (1 << OCIE0A) | (1 << OCIE0B);

von Sven K. (quotschmacher)


Lesenswert?

Wolfgang schrieb:
> Ein Arduino Duemilanove ist kein Arduino Due.
>
> Auf dem Arduino Due sitzt ein SAM3X8E ARM Cortex-M3 Controller.

wurde doch davor jetzt schon ausgiebigst geklärt...

von Thomas E. (thomase)


Lesenswert?

Sven K. schrieb:
> wurde doch davor jetzt schon ausgiebigst geklärt...

Aber noch nicht von jedem.

von hfhd (Gast)


Lesenswert?

Lukas B. schrieb:
> TIMSK0 = (1 << OCIE0A) | (1 << OCIE0B);

die zeile hatte ich auch nur mit den passenden ISR im kopf

PWM ohne ISR geht , JA
aber dann ohne das TIMSKx


hab grad irgndwo ne Lüftersteuerung gefunden
1
  PORTD   &= ~(1<<PD3);
2
  DDRD  |=  (1<<PD3);   // luefter
3
4
  TCCR2A  = (1<<WGM21)| (1<<WGM00);
5
  TCCR2B  = (1<<CS20) |(1<<CS21)|(1<<CS22); 
6
7
  if( ocrval ){
8
       TCCR2A  |=  (1<<COM2B1);      
9
    if( ocrval < 40)
10
      OCR2B = ocrval ;
11
    else  
12
      OCR2B = 40 ;
13
  }else{
14
    TCCR2A  &= ~(1<<COM2B1);
15
  }

von Muffelmutter (Gast)


Lesenswert?

Sven K. schrieb:
> Wolfgang schrieb:
>> Ein Arduino Duemilanove ist kein Arduino Due.
>>
>> Auf dem Arduino Due sitzt ein SAM3X8E ARM Cortex-M3 Controller.
>
> wurde doch davor jetzt schon ausgiebigst geklärt...

Das sind die 2 oder 3 Typen, die zwar nichts zur Beantwortung der Frage 
beitragen können, aber dafür einen Riesenspaß beim Verwirren der Leser 
haben. Fast immer heißen die Thomas oder Joachim. Manchmal auch 
Wolfgang.

Wie Fußpilz -auch ganz schlecht loszuwerden.
:(

von Lukas B. (lmwb)


Lesenswert?

S. Landolt schrieb:
>> ISR braucht man nicht bei Fast PWM
>
> Korrekt. Nur - weshalb werden die Interrupts dann freigegeben?
>
>
>> /*Interrupt enable*/
>>    TIMSK0 = (1 << OCIE0A) | (1 << OCIE0B);

Super! Danke für den Tipp, das war der Hacken :)

Habe es auskommentiert und siehe da, alles funktioniert wie gewollt. Ich 
dachte mir der Interrupt Controller des Timers muss aktiv sein damit der 
OC0A Pin Toggelt aber "again what learned" wie der Sachse sagt.

Vielen Dank für die schnellen Reaktionen und Hilfestellungen. Das war 
meine erste Anfrage und gleich ein Erfolgserlebnis.

von hfhd (Gast)


Lesenswert?

hfhd schrieb:
> aber dann ohne das TIMSKx

oder mit dem TIMSKx  aber dann die passenden ISR's platzieren

zB:
1
ISR(TIMER1_COMPA_vect) {
2
3
}

von Lukas B. (lmwb)


Lesenswert?

Haken nicht Hacken!

Sollte ich den Chat noch als gelöst markieren oder so was?

von Joachim B. (jar)


Lesenswert?

Muffelmutter schrieb:
> die zwar nichts zur Beantwortung der Frage
> beitragen können

ah sehr informativ, so richtig feige aus der Deckung Ex Stasi?

Ich vermisse deinen Beitrag zur Beantwortung der Frage.....

von Peter D. (peda)


Lesenswert?

Lukas B. schrieb:
> Sollte ich den Chat noch als gelöst markieren oder so was?

Das wäre nett.
Du solltest Deinen Startpost ja editieren können.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lukas B. schrieb:
> Habe es auskommentiert und siehe da, alles funktioniert wie gewollt.

Auch wenn es jetzt läuft, solltest Du Leos Rat in 
Beitrag "Re: AVR Atmega328P Fast PWM beeinflusst UART" beherzigen. Die 
rechte Seite eines #defines sollte man immer klammern. Sonst kann das 
bei weiteren Berechnungen ziemlich in die Hose gehen. Leo erklärt in 
seinem Beitrag auch, warum.

Ersetze bitte:
1
#define MYUBRR F_CPU/16/BAUD-1

durch:
1
#define MYUBRR (F_CPU/16/BAUD-1)

: Bearbeitet durch Moderator
von Lukas B. (lmwb)


Lesenswert?

Frank M. schrieb:
> Ersetze bitte:#define MYUBRR F_CPU/16/BAUD-1
>
> durch:#define MYUBRR (F_CPU/16/BAUD-1)

jeb, danke für den Hinweis, habe ich natürlich umgesetzt. Der Compiler 
hatte eh davor gewarnt, jetzt weiß ich auch warum.

von Bernd K. (prof7bit)


Lesenswert?

Lukas B. schrieb:
> Sollte ich den Chat noch als gelöst markieren oder so was?

Das ist kein Chat. Wir befinden uns in einem Forum.

von Dietrich L. (dietrichl)


Lesenswert?

Was mir noch aufgefallen ist:

Lukas B. schrieb:
>     DDRD = (1 << PIND6);
>     DDRD = (1 << PIND5);

Entweder ist die erste Zeile überflüssig, oder es fehlt in der zweiten 
Zeile das ODER:  DDRD |= (1 << PIND5);

von Lukas B. (lmwb)


Lesenswert?

Dietrich L. schrieb:
> Entweder ist die erste Zeile überflüssig, oder es fehlt in der zweiten
> Zeile das ODER:  DDRD |= (1 << PIND5);

Sehr aufmerksam, danke für den Hinweis. Das ist tatsächlich "nur" eine 
Schlamperei. Das Oder fehlt, bzw. konnte ich mich nicht entscheiden 
welchen Pin ich benutzte.

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.