Forum: Mikrocontroller und Digitale Elektronik Atmega32U4 configuration so korrekt?


von Philip P. (nosuchnick)


Angehängte Dateien:

Lesenswert?

Ich bin gerade dabei bei einem neuen Projekt eine grundlegende 
Funktionsprüfung zu machen.

Allerdings scheint bei dem Atmega32U4 die PWM nur auf Kanal OC4D zu 
funktionieren, OC4A und OC4B bleiben auf 0.

Im Anhang findet ihr den Schaltplan, Layout, das verwendete Testprogram 
und eine Oszi Aufnahme von dem funktionierenden Kanal.

Der Atmega ist auf 8 MHz internen Takt eingestellt, die genauen Fuse 
bits sind:
1
low      : 0xe2
2
high     : 0xd8
3
extended : 0xcb

Ich hab zwar nur ein recht einfaches Pocket Oszilloskop, aber wenn ich 
damit an den Vias oben neben dem Widerstands Array (neben der 
Stiftleiste) messe, bekomme bei OC4D ein schönes Rechteck, und bei den 
beiden anderen nur eine glatte 0V Linie. Die Messpunkt ist direkt das 
Signal V*_PWM, vor dem R3-* Widerstand.

Ich kann mir jetzt mehrere Fehlerszenarien vorstellen. Der Atmega könnte 
defekt oder nicht richtig verlötet sein. Alternativ könnten die beiden 
flachen Signale irgendwo kurzgeschlossen sein. Ich hoffe aber, dass es 
nur ein Konfigurationsfehler ist. Ich würde ungern mit dem QFN Paket 
weiter rumpfuschen.

Falls irgendwer ein Softwarefehler finden kann, würde ich mich sehr 
freuen!


*Ergänzung:*
Wenn ich PC7 und PB6 im Setup auf High stelle, messe ich an den Vias 
einen entsprechenden Pegel. Ich gehe also erstmal davon aus, dass der 
Chip richtig sitzt, und die Ports generell noch funktionieren.

von Philip P. (nosuchnick)


Lesenswert?

Ich hab das gleiche Programm gerade noch mal auf einem anderen 
Atmega32U4 ausprobiert, und das Ergebnis ist gleich. Auch hier 
funktioniert die PWM nur auf PD7 / OC4D.

Ich gehe also mal davon aus, dass es die PWM Register noch falsch 
eingestellt sind, aber ich kann nicht wirklich erkennen was falsch ist.

von Nickname (Gast)


Lesenswert?

Hi,

hier läuft ein ATMEGA32U4 mit 3 PWM Kanälen...



Der relevante Programmteile dürfen folgende Zeilen sein


1
// 32, PC7 ... 31, PC6(NOT OCR4A)
2
#define PWM_GREEN OCR4A
3
// 30, PB6 ... 29, PB5(NOT OCR4B)
4
#define PWM_BLUE OCR4B
5
// 27, PD7 ... 29, PD6(NOT OCR4D)
6
#define PWM_RED OCR4D
7
 
8
9
10
void SetupPWM(void){
11
12
  //PWM Ausgänge definieren
13
  DDRB |= (1<<DDB6)|(1<<DDB5);
14
  DDRC |= (1<<DDC6)|(1<<DDC7);
15
  DDRD |= (1<<DDD6)|(1<<DDD7);
16
17
  // Phasen und Frequenz korrekte PWM OCR4A,OCR4B und 
18
  // OCRA4,OCR4B negiert verbinden
19
  // PWM4A und PWM4B freigeben 
20
  TCCR4A |= (1<<COM4A0)|(1<<COM4B0)|(1<<PWM4A)|(1<<PWM4B);
21
  //Vorteiler 256  (120Hz)
22
  TCCR4B |= (1<<CS43)|(1<<CS40);
23
  // Phasen und Frequenz korrekte PWM OCR4D und 
24
  // OCR4D negiert verbinden, PWM4D freigeben
25
  TCCR4C |= (1<<COM4D0)|(1<<PWM4D);
26
  //Phasen und Frequenz korrekte PWM aktivieren
27
  TCCR4D |= (1<<WGM40);
28
  //PWM Auflösung auf 8-Bit einstellen
29
  OCR4C |= 0xFF;
30
}
31
32
void OutputRGB(uint8_t r, uint8_t g, uint8_t b) {
33
  PWM_RED   = r;
34
  PWM_GREEN = g;
35
  PWM_BLUE  = b;
36
}

mfg, nickname

von Philip P. (nosuchnick)


Lesenswert?

Vielen Dank!

War ein ziemlicher Dummer Fehler:

In
1
TCCR4C = (1 << COM4D1) | (1 << PWM4D);

hab ich die shadow bits für COM4AX und COM4BX überschrieben. mit
1
TCCR4C |= (1 << COM4D1) | (1 << PWM4D);

funktionierts.

Normalerweise mach ich im Setup bei Countern gerne die direkte 
Zuweisung, um sicher zu gehen, dass alles genau so ist, wie ich es gerne 
haben will.

Allerdings sollte man dann auch wirklich auf alle Bits achten.

Ausserdem hab ich noch ein bischen mit der PLL gespielt, und gemerkt, 
dass man den Counter anscheinend sogar mit 96 MHz betreiben kann. (~100 
kHz periode bei 10 bit Auflösung)


Für die Nachwelt hier noch der komplette code:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
6
void setupPLL(void){
7
  // set prescaler to 1
8
  PLLCSR &= ~(1 << PINDIV);
9
  // select internal RC osci
10
  PLLFRQ |= (1<< PINMUX);
11
  // set PLL freq to 96 MHz
12
  PLLFRQ |=  ((1 << PDIV3) | (1 << PDIV1)); 
13
  PLLFRQ &= ~((1 << PDIV2) | (1 << PDIV0));
14
15
  // divide by 2 for 48 Mhz USB
16
  PLLFRQ |= (1<< PLLUSB);
17
  // divide by 1 for 96 Mhz high speed pwm
18
  PLLFRQ |=  (1 << PLLTM0);
19
  PLLFRQ &= ~(1 << PLLTM1);
20
21
  // enable PLL
22
  PLLCSR |= (1 << PLLE);
23
}
24
25
void setupPWM(void){
26
  // Set the Output pins
27
  // PB6 = OC4B channel 2
28
  DDRB  |= (1 << 6);
29
  PORTB |= (1 << 6);
30
  
31
  // PC7 = OC4A channel 1
32
  DDRC  |= (1 << 7);
33
  PORTC |= (1 << 7);
34
35
  // PD7 = OC4D channel 3
36
  DDRD  |= (1 << 7);
37
  PORTD |= (1 << 7);
38
  
39
  // Clear on Compare match, enable PWM
40
  TCCR4A |= (1 << COM4A1) | (1 << PWM4A) | (1 << COM4B1) | (1 << PWM4B);
41
  // CS40, full clock
42
  TCCR4B |=  1 << CS40;
43
  // Clear on Compare match, enable PWM
44
  TCCR4C |= (1 << COM4D1) | (1 << PWM4D);
45
  // Fast PWM
46
  TCCR4D &= ~((1 << WGM41) | (1 << WGM40));
47
48
  // Set top to 1023
49
  TC4H = 3;
50
  OCR4C = 0xFF;
51
}
52
53
void setPWM(uint8_t channel, uint16_t value){
54
  uint8_t high = ((value >> 8) & 0x03);
55
  uint8_t low  = (value & 0xFF);
56
  switch(channel){
57
    case 0:
58
      TC4H  = high;
59
      OCR4A = low; 
60
      break;
61
      
62
    case 1:
63
      TC4H  = high;
64
      OCR4B = low; 
65
      break;
66
      
67
    case 2:
68
      TC4H  = high;
69
      OCR4D = low; 
70
      break;
71
    
72
    default:
73
      break;
74
  }
75
}
76
77
int main(void){
78
  setupPLL();
79
  setupPWM();
80
  
81
  setPWM(0, 512);
82
  setPWM(1, 512);
83
  setPWM(2, 512);
84
85
  while(1){
86
  }
87
88
  return 0;
89
}

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.